public class Student {
int score;
int age;
String name;
Computer computer;
public void study() {
System.out.println("studying...");
}
}
public class Computer {
int price;
String brand;
}
public class Test {
public static void main(String[] args) {
Student stu = new Student();
stu.name = "xiaoming";
stu.age = 10;
stu.study();
Computer c = new Computer();
c.brand = "Hasse";
System.out.println(c.brand);
stu.computer = c;
System.out.println(stu.computer.brand);
// System.out.println("----------------------------------------");
//
// c.brand = "Dell";
//
// System.out.println(c.brand);
// System.out.println(stu.computer.brand);
//
// System.out.println(stu.computer.brand == c.brand);
}
}
通过类加载器把Test类的字节码文件加载到栈的方法区内,Test类加载的信息有:①类的代码信息 ②静态方法、静态变量(静态区)③字符串常亮(常量池)④构造方法、普通方法(方法) 调用main方法,在栈中创建一个栈帧(后进先出),用于执行main方法.调用main方法,在栈中创建一个栈帧(后进先出),用于执行main方法. 发现Student stu = new Student(); 在方法区内查找有没有Student类的代码信息,没有的话jvm通过类加载器将Student类的.class字节码文件加载到内存中.发现Student stu = new Student(); 在方法区内查找有没有Student类的代码信息,没有的话jvm通过类加载器将Student类的.class字节码文件加载到内存中. Student stu = new Student(); 方法中有引用变量、局部变量都存放在main方法的栈帧中;Student stu = new Student(); 方法中有引用变量、局部变量都存放在main方法的栈帧中; Student stu = new Student(); 调用Student类的构造方法,在该线程的栈中创建一个栈帧,构造方法创建出一个实例对象,存放在堆内存中,对象中存放类的实例变量. int score, int age属于基本数据类型,jvm会将其的值初始化为0,String name为引用类型(字符串),jvm会将其默认为null;Student stu = new Student(); 调用Student类的构造方法,在该线程的栈中创建一个栈帧,构造方法创建出一个实例对象,存放在堆内存中,对象中存放类的实例变量. int score, int age属于基本数据类型,jvm会将其的值初始化为0,String name为引用类型(字符串),jvm会将其默认为null; 之后来到了Computer computer; 这时发现了Computer类,jvm加载该类的字节码文件到方法区中;computer也为引用类型,默认为null; 对象中的study()方法存放着累着study方法的地址,调用该方法时直接去类中找;之后来到了Computer computer; 这时发现了Computer类,jvm加载该类的字节码文件到方法区中;computer也为引用类型,默认为null; 对象中的study()方法存放着累着study方法的地址,调用该方法时直接去类中找; 实例对象创建完成之后, Student构造方法的栈帧出栈(被jvm垃圾回收机制销毁),返回值(返回一个对象)压入调用该方法的栈帧的操作数栈中.此时该线程的顶栈是主调方法main方法的栈帧.实例对象创建完成之后, Student构造方法的栈帧出栈(被jvm垃圾回收机制销毁),返回值(返回一个对象)压入调用该方法的栈帧的操作数栈中.此时该线程的顶栈是主调方法main方法的栈帧. 每个实例对象创建完成会生成了一个4字节16进制的内存地址,在栈中的引用变量stu中存放该地址,即栈中的stu变量指向堆内存中的Student实例对象;.每个实例对象创建完成会生成了一个4字节16进制的内存地址,在栈中的引用变量stu中存放该地址,即栈中的stu变量指向堆内存中的Student实例对象;. stu.name = “xiaoming”; stu通过引用Student实例对象的name属性,在Test类的字符串常量池中创建了"xiaoming"字符串对象;将该对象的地址告诉实例变量name;name通过地址指向常量池的"xiaoming"常量;stu.age = 10; 栈帧中的stu通过地址找到了对象的age变量,由于age是基本数据类型,因此该实例变量被直接赋值为10; stu.age = 10; 栈帧中的stu通过地址找到了对象的age变量,由于age是基本数据类型,因此该实例变量被直接赋值为10; 引用变量stu通过地址调用堆内存中对象的study()方法,study()方法又通过地址0x13c5指向方法区中类信息的方法,然后调用该方法;引用变量stu通过地址调用堆内存中对象的study()方法,study()方法又通过地址0x13c5指向方法区中类信息的方法,然后调用该方法;
Computer c = new Computer();jvm在方法区中查找computer类的代码信息,发现有了,就不再加载; Computer c = new Computer();在main方法的栈帧中开辟一个局部变量c,该变量为引用类型; Computer c = new Computer(); 调用Computer的构造方法,在栈帧创建一个栈帧;该构造方法在堆内存中实例化一个对象; Computer的构造方法出栈,返回刚刚创建的Computer对象的地址到主调方法main方法栈帧中的操作数栈中;构造方法出栈,随机被jvm的gc机制销毁,当前线程的顶栈重新回到main方法的栈帧;(只有虚拟机的顶栈才是有效的) 之后经过操作数栈的算术运算将地址传递给main方法的局部变量c,c中存放Computer类的对象的地址,指向该对象; c.brand = “Hasse” 引用变量c通过内部存放的地址找到了堆内存中的对象,并指向对象中的实例变量brand,将在Test常量池中创建了"Hasse"字符串对象,并将该对象的地址存到brand内存中; stu.computer = c; 通过引用变量stu找到了堆内存中的Student对象,指向了该对象的实例变量 computer,此时该变量内存中为系统默认值null; stu.computer = c; 通过引用变量stu找到了堆内存中的Student对象,指向了该对象的实例变量 computer,此时该变量内存中为系统默认值null; stu.computer = c; 将main方法栈帧中的局部变量c内存中存放的地址赋值给实例变量 computer;此时computer也指向了堆中的Computer对象;stu.computer = c; 将main方法栈帧中的局部变量c内存中存放的地址赋值给实例变量 computer;此时computer也指向了堆中的Computer对象; c.brand = “Dell”; c引用变量通过地址找到了Computer对象,在字符串常量池中创建了"Dell"对象,将"Dell"对象的地址传给实例变量brand;c.brand = “Dell”; c引用变量通过地址找到了Computer对象,在字符串常量池中创建了"Dell"对象,将"Dell"对象的地址传给实例变量brand;