java引用类型数据的补充——数组和类创建对象使用的内存图

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

上次主要介绍了java的引用类型数据,有画出String的内存图,这次补充一下类和数组创建对象使用的内存图。


一、数组对象的内存图

1.一维数组内存图

且看下面代码

public class Test {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33};//静态初始化
        arr[0] = 44;
        arr[1] = 55;
        arr[2] = 66;
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

A.将类加载到方法区,就是将类的字节码的文件加载到方法区

B.JVM自动调用方法区的main方法,进入到栈内存

C.main方法进入到栈内存后开始执行第一行代码。第一行代码是数组的静态初始化,长度随赋值的个数决定为3。数组是引用类型视为一个类在堆内存开辟一个新的空间给这个arr数组对象。并将数组的引用地址给到栈内存main方法中arr这个变量。

D.接下来执行main方法下面接下来的三行代码,先找到arr的引用地址,到达堆内存将对应的三个数值更改。

E.最后执行main方法中最后三行代码,先找到arr的引用地址,到达堆内存将对应的三个数值输出到控制台。

F.main方法走完程序结束。 

2.两个数组指向相同内存图

除了main方法第二句,其他的内存走向都和上面相同。

第二句就是多一个变量指向堆内存这个对象地址,输出结果都是一个对象的内容,结果相同。

 

3.二维数组内存图 

public static void main(String[] args) {
    int[][] arr = new int[2][3];
    int[] arr1 = {11, 22, 33};
    int[] arr2 = {44, 55, 66};
    arr[0] = arr1;
    arr[1] = arr2;
}

A.将类加载到方法区,就是将类的字节码的文件加载到方法区

B.JVM自动调用方法区的main方法,进入到栈内存

C. main方法进入到栈内存后开始执行第一行代码。第一行代码是二维数组的动态态初始化,长度由参数决定为2,3。数组是引用类型视为一个类在堆内存开辟一个新的空间给这个arr数组对象。并将数组的引用地址给到栈内存main方法中arr这个变量。因为是二维数组,所以这里还要开辟两个一维数组的空间,指向新开辟的二维数组。

D.再指向main方法后面两行的代码,在堆内存开辟两个空间,赋值后引用地址分别指向arr1,arr2

E.然后指向main方法第四行代码,将arr二维数组在堆内存中arr[0]的内容引用改成arr1

 

F. 最后指向main方法最后一行代码,将arr二维数组在堆内存中arr[1]的内容引用改成arr2

G.main方法走完程序结束。 


二、类对象内存图

1.单个对象内存图

代码如下(示例):

public class Student {
    String name;
    int age;
    public void study(){
        System.out.println("学习Java");
    }    
    public void eat(){
        System.out.println("吃饭");
    }
}
public class TestStudent {
    public static void main(String[] args) {
        Student stu = new Student();
        System.out.println(stu); //输出对象的地址         
        System.out.println(stu.name);
        System.out.println(stu.age);
        stu.name = "张三";
        stu.age = 23;
        System.out.println(stu.name);
        System.out.println(stu.age);      
        stu.study();
        stu.eat();
    }
}

A.类的字节码文件进入方法区,main方法在TestStudent类,所以先加载字节码文件TestStudent.class到方法区,再将main方法进栈

B. main方法进入到栈内存后开始执行第一行代码。因为要用到Student类就再将Student类的字节码文件Student.class加载到方法区。

C.new 一个Student类型对象stu,就会在堆内存开辟一个空间存放对象,对象的内容按照字节码文件的内容设计成员变量和方法,变量为默认值,方法记录方法区Student.class成员方法的地址。stu这个变量记录新对象在堆内存的引用地址。

 

D. main方法第二行代码要输出stu,因为stu记录的是对象的引用地址,所以输出的是地址码。

E. main方法第三、四行代码要输出stu.name,stu.age。通过stu记录的地址找到在堆内存中的对象,发现name和age都是默认值,将其输出 null 0.

F.接下来这四行跟E都一样, 通过stu记录的地址找到在堆内存中的对象,进行赋值后输出

 G.接下来执行stu.study();   先通过stu记录的地址找到在堆内存中的对象,再通过对象的成员方法引用地址找到方法区的成员方法,最后study方法进栈。打印“学习Java”。

H.study方法打印完后出栈。

 

I.跟步骤G、H一样执行最后一句代码,输出“吃饭” 

2.两个对象内存图

代码示例:

public class Student {
    String name;
    int age;
    public void study(){
        System.out.println("学习Java");
    }
    public void eat(){
        System.out.println("吃饭");
    }
}
public class Test {
    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.name = "张三";
        stu1.age = 23;
        Student stu2 = new Student();
        stu2.name = "李四";
        stu2.age = 24;
        System.out.println(stu1.name);
        System.out.println(stu2.age);
        stu1.study();
        stu2.study();
    }
}

 跟单个对象不同的是这个new两个对象,所以在堆内存开辟两个空间,因为数据类型都是Student类,所以两个对象的成员方法引用地址都是一样的,输出一样。

 3.两个引用指向相同内存图

public class Student {
    String name;
    int age;
    public void study(){
        System.out.println("学习Java");
    }
    public void eat(){
        System.out.println("吃饭");
    }
}
public class Test {
    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.name = "钢门吹雪";
        Student stu2 = stu1;
        stu2.name = "西域狂鸭";
        System.out.println(stu1.name);   
        System.out.println(stu2.name);    
    }
}

 上面这段代码的内存图要改动的和前面数组的两个数组指向相同内存图的改动一年,两个变量指向同一个堆内存对象地址。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值