【Java】内存中的数组

简介: 【Java】内存中的数组

【Java】内存中的数组

 首先解决前面的一个问题,能不能给数组只分配内存空间,不赋初始值?

       答案是肯定不行的,当我们给数组元素分配内存时,内存空间存放的内容就是该数组元素的值,如果内容是空的,那也是一个值——null。

       我们讲过数组是一个引用数据类型,这就意味着数组元素和数组变量在内存中是分开存放的。例如我们创建一个数组int[] a = {1,2,3};a只是一个引用变量,里面只存放了一个地址,实际的数据1,2,3被存放在堆内存中,引用变量被存放在栈内存中。举一个简单的例子,我们在超市门口寄存东西的时候,那里有好多小柜子,每个柜子上面都有一个编号,我们把东西放进柜子里面,然后在一个小册子上记下自己的名字和对应柜子的编号。这就像一个数组的创建,柜子就是堆内存,里面存放了真正的数据,编号就像一个地址,用来标记柜子的位置,你在小册子上面登记的名字就是那个数组的名字,就和一个地址对应而已。

       如果堆内存中数组不再有任何引用变量指向自己,则这个数组将变成垃圾,这时候就会被Java的垃圾回收机制回收。

       在讲解内存中的数组之前,我们了解一下内存,Java是怎么使用内存的呢?容我小小的介绍一下java的内存机制。在Java里面把内存划分成两种:一种是栈内存,另一种是堆内存。

       在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

       堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。

       这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针,只不过被隐藏了,我们看不到。

       再来谈谈数组,我们之前讲过,数组是一种引用类型,既然是引用类型,那就存在两部分,引用变量和变量的值。引用变量为数组的名称,存放在栈内存中,变量的值也就是数组中存放的数据,存放在堆内存中。当一个堆内存中的对象没有任何引用变量引用它时,垃圾回收器就会在合适的时候回收这个对象占用的内存。

       看下面数组初始化的代码:

int[]  a;
a = new int[5];

       第一行代码int[] a只是声明定义了一个数组,并没有为这个数组赋值,内存中的变化如下图所示;

image.png

       执行代码int[] a后,只是在栈内存中定义了一个空引用,这个引用并没有只想任何有效的内存,这时候如果使用这个指针的话,就会抛出空指针异常(NullPointerException)。

       当执行a = new int[5]这段代码后,数组就会被动态初始化,系统会给数组分配内存空间,并且会有默认值。这时候内存中存储示意图如下所示:

image.png

       这就是基本类型数组的初始化,看起来比较简单,接着看一下引用类型的数组。

       当引用类型的数组初始化时,情况会复杂一些,再举一个例子,首先定义一个类Num,所有的类都是引用类型。

public class Num {
   public int i;
   public double d;
}

       接着定义一个对象数组,并对这个数组进行初始化操作,接着给每个元素指定一个值。代码如下所示:

image.png

       结合数组在内存中的变化情况,分析一下代码的执行过程

       首先当我们定义数组时,执行Num[] nums;代码,这时候在栈内存中定义了一个引用变量,就像C语言中的指针,而且还是一个空指针。

image.png

       动态初始化以后,系统会分配地址,指针就有地址了,因为数组里面放的引用变量,所以数组元素默认值为null,这时候还不能使用数组里面的元素。

image.png

       然后定义了两个实例变量big和sma,根据上面的解释,我们会发现这时候使用了四块内存。堆内存里面放了两个Num的实例。

image.png

       接着执行下面的代码,把big赋给属猪中的第一个元素,把sma赋给数组中的第二个元素。这时候数组中的元素就不再是空了。

image.png

       如上图所示,这时候big和nums[0]指向同一块内存区,所以这两个变量代表同一个对象,所以对比的结果为true;这时候如果修改big变量所指向的实例或者nums[0]指向的实例,都是修改同一块区域,再调用另一个引用变量时,已经是修改以后的实例了,实际使用过程中需要多加注意。


       根据上面的结果,我们来考虑一个问题,在内存中,多维数组是怎么存储的呢?聪明的你是否想到了呢?

   最后附上手绘版二维数组的存储示意图,仅供参考:

image.png

目录
相关文章
|
14天前
|
监控 算法 Java
Java中的内存管理:理解Garbage Collection机制
本文将深入探讨Java编程语言中的内存管理,特别是垃圾回收(Garbage Collection, GC)机制。我们将从基础概念开始,逐步解析垃圾回收的工作原理、不同类型的垃圾回收器以及它们在实际项目中的应用。通过实际案例,读者将能更好地理解Java应用的性能调优技巧及最佳实践。
55 0
|
9天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理
|
1天前
|
存储 安全 Java
Java数组(Arrays)详解
Java 中的数组是一种用于存储固定数量同类型数据的高效数据结构,支持连续内存存储和随机访问。数组可以声明并初始化,通过索引访问和修改元素,获取长度,使用循环遍历,支持多维形式,并可通过 `Arrays` 类的方法进行复制和排序。数组具有固定大小和类型安全的特点,但需注意越界等问题。灵活运用数组能显著提升编程效率。
|
4天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
14 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
11天前
|
Java 编译器
深入理解Java内存模型:从基础到高级
本文旨在通过通俗易懂的方式,引导读者深入理解Java内存模型(JMM)的核心概念和工作原理。我们将从简单的基础知识入手,逐步探讨重排序、顺序一致性问题以及volatile关键字的实现机制等高级主题。希望通过这篇文章,你能够对Java内存模型有一个清晰、全面的认识,并在实际编程中有效地避免并发问题。
|
8天前
|
存储 算法 Java
深入理解Java内存管理
本文将通过通俗易懂的语言,详细解析Java的内存管理机制。从JVM的内存结构入手,探讨堆、栈、方法区等区域的具体作用和原理。进一步分析垃圾回收机制及其调优方法,最后讨论内存泄漏的常见场景及防范措施。希望通过这篇文章,帮助读者更好地理解和优化Java应用的内存使用。
|
14天前
|
存储 Java 数据处理
Java 数组的高级用法
在 Java 中,数组不仅可以存储同类型的数据,还支持多种高级用法,如多维数组(常用于矩阵)、动态创建数组、克隆数组、使用 `java.util.Arrays` 进行排序和搜索、与集合相互转换、增强 for 循环遍历、匿名数组传递以及利用 `Arrays.equals()` 比较数组内容。这些技巧能提升代码的灵活性和可读性,适用于更复杂的数据处理场景。
|
13天前
|
监控 算法 Java
Java中的内存管理与垃圾回收机制
本文将深入探讨Java编程语言中的内存管理方式,特别是垃圾回收(Garbage Collection, GC)机制。我们将了解Java虚拟机(JVM)如何自动管理内存,包括对象创建、内存分配以及不使用对象的回收过程。同时,我们还将讨论不同的垃圾回收算法及其在不同场景下的应用。
|
12天前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
19天前
|
监控 算法 Java
Java中的内存管理:理解垃圾回收机制的深度剖析
在Java编程语言中,内存管理是一个核心概念。本文将深入探讨Java的垃圾回收(GC)机制,解析其工作原理、重要性以及优化方法。通过本文,您不仅会了解到基础的GC知识,还将掌握如何在实际开发中高效利用这一机制。
下一篇
无影云桌面