天天看点

《java练级之路》之数组为什么成为引用类型

🌀🌀🌀作者:@小鱼不会骑车

🍁🍁🍁专栏:《java练级之旅》

🎀🎀🎀个人简介:一名专科大一在读的小比特,努力学习编程是我唯一的出路😎😎😎

《java练级之路》之数组为什么成为引用类型
🙈🙈🙈作者心里话
小鱼一直都是秉承着“开开心心看博客,快快乐乐学知识”这个观点来给大家用一些接地气的话进行讲解,可能会有人觉得小鱼太墨迹了,小鱼这里也很乐意接受大家的意见,会进行采纳,大家也可以指出小鱼的不足,小鱼也会积极的进行改变,总之,愿我们越来越优秀

前言

在这篇文章中,小鱼会细致的讲解大家在初识java时对于java中数组的认知,前面一篇文章讲解了数组的创建及初始化,那么这片文章呢,就会讲到关于数组在内存中是如何存储的,准备好了吗各位开始发车了😜

《java练级之路》之数组为什么成为引用类型

(数组是引用类型)

🍎 初识JVM的内存分布

💡在我们的java中,内存是一段连续的存储空间,主要用来存储程序运行时数据的。比如:

  1. 程序运行时代码需要加载到内存
  2. 程序运行产生的中间数据要存放在内存
  3. 程序中的常量也要保存
  4. 有些数据可能需要长时间存储,而有些数据当方法运行结束后就要被销毁
如果对内存中存储的数据不加区分的随意存储,那对内存管理起来将会非常麻烦。

因此JVM也对所使用的内存按照功能的不同进行了划分:

《java练级之路》之数组为什么成为引用类型

总共有五部分,

  • 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址
  • 虚拟机栈(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
  • 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量.在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的。
  • 堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。
  • 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域

但是我们在学习这一篇的内容时只会涉及到栈区和堆区,稍后会进行详细讲解。

🍎 基本类型变量与引用类型变量

🍓1. 基本数据类型和引用类型变量

🐵我们接下来用三种方式开辟数组

int[]array1={1,2,3,4};//开辟一个静态数组
int[]array2=new int[]{1,2,3,4};//同上(new int []可以舍去)
int[]array3=new int[4];//开辟一个动态数组
           

这是一个int类型,在内存中的存放方式如图

int a=10;
           
《java练级之路》之数组为什么成为引用类型

a在main函数里是局部变量,所以在栈上分配内存。

那么我们的数组呢?在内存中是如何存储的?🧐

《java练级之路》之数组为什么成为引用类型

在内存中,堆区比栈区大一些❗️❗️❗️

👉大家看,我们的第一个和第二个开辟数组的方式其实是一样的,都是new一个空间出来,那么new出来的空间是哪里的呢?其实就是堆上的,我们从堆上开辟了一块内存,用来存放这个而数组的值,

我们假设array1在堆中开辟内存的地址是0x123,那么我们变量array1存放的就是0x123,也就是存放堆上开辟空间的地址。

《java练级之路》之数组为什么成为引用类型

🌈大家刚才看到了

int a=10

,在栈上存放的是int类型的数据,但是

int[]arry1

是一个引用类型,存放的是堆上开辟的内存的地址,那我们就可以称array1这种变量为引用变量(引用),这时候我们就可以通过array1引用变量中存放的地址,找到这块开辟的内存空间,

✅专业术语:array1指向了一个对象,这个对象就是在堆上开辟的内存

《java练级之路》之数组为什么成为引用类型

就这样,我们就可以通过这个地址找到这块空间。

int a=10;
int []array={1,2,3,4};
           

✅总结上述代码

  • a,array都是函数内部创建的变量,因此,其空间都在main方法对应的栈帧中分配。
  • a是内置类型的变量,因此其空间保存的就是给该变量初始化的值。
  • array是数组类型的引用变量,其内部保存的内容可以简单理解成,是数组在堆空间中的首地址。
《java练级之路》之数组为什么成为引用类型

🍎 再谈引用变量

🍓 1. 第一道基础题

接下来给大家看一串代码

int[]array1={1,2,3,4};
        array1[0]=99;
        int[]array2=array1;
        array2[0]=100;
        System.out.println(Arrays.toString(array1));
        System.out.println(Arrays.toString(array2));
           

🐻大家猜第一个打印什么第二个打印什么?

大家现在可以暂时思考一下,心中有答案之后再往下划,看看答案是不是跟自己想的一样。

《java练级之路》之数组为什么成为引用类型
《java练级之路》之数组为什么成为引用类型

🐧好的,接下来就会给大家进行解析,我们先把代码拷贝到画图板

1️⃣我们现在进行了第一步,开辟空间,

《java练级之路》之数组为什么成为引用类型

2️⃣将首元素改为99

《java练级之路》之数组为什么成为引用类型

3️⃣将array1的值给array2

《java练级之路》之数组为什么成为引用类型

我们将a赋值给b我们的b就是10,那我们把array1给array2呢?因为我们的array1中存放的是地址,所以我们把array1的值赋值给array2就是把地址赋值给array2,如图

《java练级之路》之数组为什么成为引用类型

所以我们的array2指向的空间也是地址为0x123的空间,

4️⃣将array2[0]的值改为100

《java练级之路》之数组为什么成为引用类型

因为我们array1和array2指向的同一块空间,所以修改array2就就是修改array1,所以我们最后的输出就是{100, 2, 3, 4}

综合上述

《java练级之路》之数组为什么成为引用类型

🍓 2. 第二道基础题

🙈好的,大家再来看这串代码(小鱼又要挖坑了呦)

int[]array1={1,2,3,4};
        int[]array2={11,22,33,44};
        array1=array2;
        array1[0]=1234;
        System.out.println(Arrays.toString(array1));
        System.out.println(Arrays.toString(array2));
           

让我们来思考思考,这个会输出什么呢?

答案就在下面

《java练级之路》之数组为什么成为引用类型

输出

《java练级之路》之数组为什么成为引用类型

大家想到的答案和这个一样嘛?

接下来小鱼给大家讲解

1️⃣第一步依旧是开辟一块空间

《java练级之路》之数组为什么成为引用类型

2️⃣就是把array2赋值给array1

《java练级之路》之数组为什么成为引用类型

这样我们array1的存放的地址和array2存放的地址就一样,我们就可以通过array1找到array2地址指向的空间,

3️⃣ 我们将array[0]的值改为1234,

《java练级之路》之数组为什么成为引用类型

🐧好的,现在我们现在就可以发现,我们的array1和array2指向的是同一块空间,并且我们的array1将下标为0的元素改为了1234,于是最后输出就得到了我们上面的答案,当然,此时由于我们的array1找不到之前的空间了,所以之前开辟的空间就会被系统自动回收,不用担心内存泄漏

✅结论

当两个引用同时指向一块对象时,通过其中任意一个引用去访问该对象并修改该对象的值,另一个引用去访问的时候,值也是被改变的

💡可以理解为对象时一个“空调”,我用这个“遥控器1”(array1)去修改它的温度之后,我的“遥控器2”(array2)再去访问这个空调,就是已经被修改的温度,当我的“遥控器2”去修改也是同理

🍎 认识null

🍓1. java中null注意事项

🌈在java当中局部变量一定要初始化不然会报错❗️❗️❗️

《java练级之路》之数组为什么成为引用类型

🍰我们的b是int类型可以赋值个0初始化,但是我们的array4呢?他是个引用,他存的是地址,该怎么做才能让他不去指向别的变量呢。我们可以用null(小写)这个就是空指针,当我们置成空指针时,array4就不指向任何对象了

int b=0;
        int[]array4=null;
        System.out.println(b);
        System.out.println(array4);
           
《java练级之路》之数组为什么成为引用类型

☀️但是呢,在我们初始化为空指针后,如果我想要访问它的第0个元素,就会报错。

int[]array4=null;
        System.out.println(array4[0]);
           
《java练级之路》之数组为什么成为引用类型

🍒这个就是咱们以后会经常涉及到的问题,也可以成为NPE,意思是空指针异常,当出现这个问题的时候,就需要去检查了,这里是8

《java练级之路》之数组为什么成为引用类型

😾这时候我们就需要根据提示

《java练级之路》之数组为什么成为引用类型

🍀我们的发现array4是null,如果我们的引用是null我们通过这个引用不管去做任何事他都会报错,

int[]array4=null;
        System.out.println(array4.length);
           

🍎 总结

  • 我们的数组是存放在哪里
  • 如何访问到这个数组
  • 数组的值是如何被修改的
  • 在访问数组时需要注意的事项
  • 如何避免空指针异常