基于下面的简单代码对其执行的内存进行一步步的分析,以更好的了解程序运行机制;代码如下:
public class Person {
String name;
int age;
public void show(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class TestPerson {
public static void main(String[] args) {
//创建p1对象
Person p1 = new Person();
p1.age = 24;
p1.name = "张三";
p1.show();
//创建p2对象
Person p2 = new Person();
p2.age = 34;
p2.name = "李四";
p2.show();
}
}
以上代码的执行结果如下:
接下来对上述代码基于内存的执行过程进行分析:
(1)以上Java代码的入口为TestPerson类中的main()方法,所以形成main方法的栈帧,如下图所示:
(2)执行代码:Person p1 = new Person();同时在方法区加载Person类信息,首先创建一个引用对象,占4个字节,然后执行构造方法创建开启一个Person的栈帧【图中未命名的栈帧为Person构造方法的栈帧】。如下图所示:
(3)同时在堆中创建一个Person对象,假设该对象的地址为:0x11,当对象创建完成后,Person构造方法的栈帧完成,将p1对象的地址0x11赋给main的p1,同时构造方法的栈帧出栈。最后结果如下图所示
(4)执行下一步,p1.age = 24; p1.name = "张三";24为基本数据类型,所以直接在对象0x11中直接赋值,而String类型的“张三”不是基本数据类型,所以在方法区创建“张三”对象,同时将“张三”对象的地址赋给name。执行后的结果如下图所示:
(5)接下来执行p1.show();首先在栈中创建p1.show()的栈帧,同时传递隐式参数this,this指当前对象。如下图所示:
在show方法中执行打印操作,打印结果为:姓名:张三,年龄:24;
打印结束后,p1.show()方法执行完毕。p1.show()出栈。如下图所示:
(6)执行代码:Person p2 = new Person();,首先创建一个引用对象,占4个字节,然后执行构造方法创建开启一个Person的栈帧【图中未命名的栈帧为Person构造方法的栈帧】。如下图所示:
(7)同时在堆中创建一个Person对象,假设该对象的地址为:0x12,当对象创建完成后,Person构造方法的栈帧完成,将p2对象的地址0x12赋给main的p2,同时构造方法的栈帧出栈。最后结果如下图所示:
(8)执行下一步,p2.age = 34; p1.name = "李四";34为基本数据类型,所以直接在对象0x12中直接赋值,而String类型的“李四”不是基本数据类型,所以在方法区创建“李四”对象,同时将“李四”对象的地址赋给name。执行后的结果如下图所示:
(9)接下来执行p2.show();首先在栈中创建p2.show()的栈帧,同时传递隐式参数this,this指当前对象。如下图所示:
在show方法中执行打印操作,打印结果为:姓名:李四,年龄:34;
打印结束后,p2.show()方法执行完毕。p2.show()出栈。如下图所示:
(10)同时:main()方法执行完成,main()方法出栈。如下图所示