前言
开启掘金成长之旅!这是我参加「掘金日新计划·12月更文挑战」的第九天,点击查看活动详情
今天给大家分享的是我对于Java对象内存的理解。
Java内存分配
- 栈
- 堆
- 方法区
- 本地方法栈
- 寄存器
方法区:字节码文件加载时进入的内存
栈内存:方法运行时所进入的内存,变量也是在这里
堆内存:new出来的东西会在这块内存中开辟空间并产生地址
当创建一个对象时Student s = new Student(),内存空间会有以下几步:
- 加载class文件
- 申明局部变量
- 在堆内存中开辟一个空间
- 默认初始化
- 显示初始化
- 构造方法初始化
- 将堆内存中的地址值赋值给左边的局部变量
一个对象的内存图
public class Student{
String name;
int age;
public void study(){
System.out.println("正在学习!");
}
}
public class studentTest{
public static void main(String[] args){
Student s = new Student();
System.out.println(s); //输出s的地址值
System.out.println(s.name+"..."+s.age); //null...0
s.name = "阿强";
s.age = 23;
System.out.println(s.name+"..."+s.age); //阿强...23
s.study(); //好好学习!
}
}
方法区存放了Student类和studentTest类的字节码(.class)文件,当代码执行到Student s = new Student(); 时,在堆内存中开辟出来一个地址值为001的空间,里面存放了Student类的所有属性、构造方法、成员方法,此时name和age均为默认值(null和0),然后再将该地址值(001)赋值给s,之后s访问name和age,对其进行赋值。最后执行s.study()时,先在方法区中找到study(),在栈内存中执行,打印“好好学习”后从栈内存中清除,接着main方法从栈内存中清除,因为s也一起被清除,所以堆内存中的Student类也成为垃圾被清除。
两个对象的内存图
public class Student{
String name;
int age;
public void study(){
System.out.println("正在学习!");
}
}
public class studentTest{
public static void main(String[] args){
Student s1 = new Student();
s1.name = "阿强";
s1.age = 23;
System.out.println(s1.name+"..."+s1.age); //阿强...23
s1.study(); //好好学习!
Student s2 = new Student();
s2.name = "阿珍";
s2.age = 24;
System.out.println(s2.name+"..."+s2.age); //阿珍...24
s2.study(); //好好学习!
}
}
两个对象就是将一个对象的操作进行两遍。值得注意的是,在创建第二个对象s2时,方法区不用再次执行一次字节码文件。
两个引用对象指向同一个对象
public class Student{
String name;
int age;
public void study(){
System.out.println("正在学习!");
}
}
public class studentTest{
public static void main(String[] args){
Student stu1 = new Student();
stu.name = "阿强";
Student stu2 = stu1;
stu.name = "阿强";
System.out.println(stu1.name+"..."+stu2.age); //阿珍...阿珍
}
}
两个引用对象指向同一个对象和上面两种情况的区别在于第二个创建的对象stu2覆盖了对象stu1,所以对象stu2的值会覆盖对象stu1,两个对象在堆内存中有相同的地址值。