7.6 创建对象内存分析
主程序实例
package com.baidu.www.oop;
import com.baidu.www.oop.demo03.Pet;
public class Application {
public static void main(String[] args) {
Pet dog =new Pet();
dog.name = "旺财";//这里的对象的属性在类中需要定义为public,否则无法调用
dog.age = 3;
dog.shout();
System.out.println(dog.name);
System.out.println(dog.age);
Pet cat = new Pet();
}
}
其他类实例
package com.baidu.www.oop.demo03;
public class Pet {
public String name;//这里设置为public是因为public的权限是比较高的
public int age;
public void shout(){
System.out.println("叫了一声");
}
}
程序运行需要加载一些程序运行的模板,所以第一步就需要把主程序中Application类中的代码信息放进内存,这里我们只是图示理解,真实的内存远比这个复杂的多。
- 在方法区加载Application这个类,这个类中有一个方法叫做main方法,此外还有一些常量池,旺财
- 在栈中压入main方法,main方法第一行代码是new了一个Pet对象
- 运行new Pet()语句
- 在方法区加载Pet类,Pet类中有属性和方法,也就是当new方法时,这个类就被加载进了内存,此时的Pet类被加载时,属性还没有被赋值。当实例化对象dog后
- 实例化对象dog后,就在栈中压入了变量dog,dog是一个引用或者一个变量名,而真正的对象是在**“堆”**中的
- 通过方法区中的类实例化了一个对象dog在栈中,而栈中的dog是被引用到了堆中的对象。而此时的堆中new的Pet中变量等还未被赋值,此时的name=null,age=0,此时还有一个自己的方法shout(),而这个shout方法调用的是方法区中Pet类中的方法。
- 经过以上几步,new Pet()这条语句就走完了,这也就是进入无参构造时所做的事情。
- 执行下一条语句dog.name赋值,这个过程就是从方法区Application中的常量池中的旺财丢给了堆中的Pet对象的name
- 执行赋值语句dog.age=3
- dog.shout()是调用了方法区中的Pet类的shout()方法,因为这两个方法是一样的,并没有传递任何参数。到此,dog对象在堆中就被赋予了值了。
- 当执行Pet cat = new Pet();语句时,此时就在栈中又压入一个引用变量名cat,这是一个引用,而引用是需要指向真实的地址,此时在堆中又会有一块空间来存放这个新的对象,地址为000X2,此时还是默认值
- 这里我们也理解了,为什么被称为引用变量名,它真正指向的是堆中的具体的对象。
- 此外,在方法区中,还有一个空间叫做静态方法区,这个区域是用于存放被Static关键字修饰的都会被存放在这里,是和类一起加载进来的,这也就是说所有的对象都可以调用这个静态方法区的数据。
- 实际上,在内存中,左侧的是栈,而右侧的都是堆,只不过在堆中有一个特殊的空间叫做方法区,堆一般是存放我们具体创建出来的对象,而栈中都是一些方法加一些变量的引用
如图