Java创建对象时的内存分析
引言
在Java中实例化对象时,我们不可避免都要用到new关键字来创建对象。
那么在一个对象被创建出来的过程里,内存做了一些什么事情呢?
本文通过简单的java内存模型来阐述对象创建过程中内存中的变化,着重于了解在new一个对象时,内存里的行为。(注:内存模型受到了极其的简化)
1、示例代码
创建一个Dog类,实例化两个对象,分别是"AHuang"和"AHui"。
//创建Dog类,定义成员变量和run方法
public class Dog{
String name;
int age;
public void run(){
System.out.println("running");
}
}
//编写测试代码
public class Test{
public static void main(String[] args){
Dog doggy1 = new Dog();
doggy1.name = "Ahuang";
doggy1.age = 1;
doggy1.shout;
Dog doggy2 = new Dog();
doggy2.name = "AHui";
doggy2.age = 5;
doggy2.shout;
}
}
2、名词解释
栈:主要用于存储main(),引用变量名等
堆:存储对象
方法区:加载类相关信息
静态方法区,和类一起加载,可以被对象直接使用
3、流程图
4、流程分析
- 程序运行时,首先加载一些关于Test类的模版信息,该Test类里含有
- main()方法
- 常量池(含AHuang,AHui等字符串)
main方法被压入栈的最底下
- 执行main方法,遇到Dog类,加载Dog类,内含
- name
- age
- run()方法
此时name,age都没有值
- main方法遇到new Dog,创建对象
-
栈内存中会为doggy1引用开辟空间
-
堆内存中会为doggy1开辟空间,此时堆内存中的doggy1对象的成员变量被默认初始化。
-
对象里的name值调用了常量池的“AHuang”字符串,调用了Dog类里的run()方法,完成自定义初始化。
-
通过构造方法完成对象初始化完毕。
-
将doggy1引用指向doggy1对象的内存。
5、总结
- 在程序运行时,主方法所在的类Test首先在方法区内被加载,主方法里调用了Dog类,于是方法区继续加载出Dog类
- 使用new关键字创建doggy对象时,Dog类生成了一个名为doggy1的引用类型,栈内存中被开辟了一片空间用于其存储,该引用类型不存储任何东西,只存储一个指向对象的地址。
- 该引用类型存储指向对象的地址,并且在堆内存中开辟一片空间,即该引用类型在堆内存中加载出一个对象,此时对象的成员方法得到加载,,对象的变量如String,int都为默认初值,即完成默认初始化。
- 方法区中Test中常量池里的值被传给对象,对象完成自定义初始化。
- doggy2同理