Java数组初始化的内存分配
1.Java数组是静态的
Java是静态语言,所以Java的数组也是静态的,即:数组被初始化后,长度不可变
静态初始化:显式指定每个数组元素的初始值,系统决定数组长度
String[] books = new String[]{"疯狂Java讲义","Thinking in Java","Java核心技术卷"};
String[] names = new String[]{"张三","李四","王五","赵六"};
动态初始化:显式指定数组的长度,系统决定每个数组元素的初始值
String[] strArr = new String[5];
以上两种初始化的内存使用情况如图所示:
动态初始化数组由系统决定每个数组元素的初始值,遵循以下规则:
- byte、short、int、long类型的数组的初始值为
0
- float、double类型的数组的初始值为
0.0
- char类型的数组的初始值为
'\u0000'
,表现为空字符''
,但要占位 - boolean类型的数组的初始值为
false
- 引用类型的数组的初始值为
null
一旦数组初始化完成,则长度不可改变,以下代码造成了数组初始化后长度可改变的假象:
books = names;
strArr = books;
System.out.println(books.length); // 4
System.out.println(strArr.length); // 4
Java的数组变量是一种引用类型的变量,数组变量并不是数组本身,它只是指向堆内存中的数组对象,改变一个数组变量所引用的数组,可以造成数组长度可变的假象。
上述代码让books数组变量和strArr数组变量都指向了names数组变量引用的数组,这样做的结果就是让三个数组变量都引用了相同的数组对象。内存图如下:
而原来strArr和books引用的数组对象的长度不会改变,由于已经没有变量引用它们,它们成为垃圾,等待垃圾回收机制来回收。此时,程序使用strArr、books、和names这三个变量时,将会访问同一个数组对象。
JavaScript是动态语言,其数组的长度可以改变:
<script type="text/javascript">var arr = [];document.write("arr的长度为:" + arr.length + "<br>"); // 0arr[0] = 1;document.write("arr的长度为:" + arr.length); // 1
</script>
2. 数组一定要初始化吗?
实际上,懂得了Java数组的内存机制后,我们可以说:数组不是必须初始化,或者说,数组初始化不仅有之前介绍的两种方法,可以完全换一种方法:
int[] nums = new int[]{1, 2, 3, 4, 5};
int[] arr;
arr = nums;
对于数组对象来说,必须初始化,也就是为该数组对象分配一块连续的内存空间,连续内存空间的长度就是数组对象的长度。
对于数组变量来说,不需要进行初始化,只需让其指向一个有效的数组对象就可以。
实际上,所有引用类型的变量,其变量本身不需要任何初始化,需要初始化的是它所引用的对象。
3. 基本类型数组的初始化
程序直接先为数组分配内存空间,再将数组元素的值存入对应的内存中。
int [] nums; ①
System.out.println(nums); ②
nums = new int[]{1, 2, 3, 4}; ③
System.out.println(nums.length); ④
我们来分析①-④步的内存:
① 定义nums数组变量后的存储示意图如下:
对于②行代码来说没有任何问题,虽然nums变量并未引用到有效的数组对象,但此时并未通过nums变量访问数组对象的方法或属性,所以没有问题。
③ 静态初始化nums数组后的存储示意图如下:
对于④行代码来说,此时访问了nums数组对象的属性,所以要求nums必须引用一个有效的对象。
当通过引用变量来访问实例属性或者调用非静态方法时,如果该引用变量还未指向有效的对象,程序就会抛出运行时异常:NullPointerException
,例如,第二行代码如果为:
System.out.println(nums.length);
就会抛出NullPointerException
误区:基本类型的数据的值存储在栈内存中
实际上,应该是所有的局部变量都保存在栈内存中,不管是基本类型还是引用类型,局部变量都保存在各自的方法栈中。
4. 引用类型数组的初始化
引用类型数组的数组元素仍然是引用类型,因此数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了该引用变量所引用的对象,包括数组和Java对象。
下面程序的执行代表了引用类型数组初始化的典型过程:
class Person{String name;int age;public void info(){System.out.println("name:" + name + ", age:" + age);}
}// 创建两个Person对象
Person p1 = new Person();
p1.name = "张三";
p1.age = 20;
Person p2 = new Person();
p2.name = "李四";
p2.age = 30;// 将两个Person对象赋给数组元素
person[0] = p1;
person[1] = p2; // 结果一样,p1和person[0]指向同一个对象
p1.info();
person[0].info();
分析内存:
5. 数组元素就是变量
当数组引用变量指向一个有效的数组对象之后,程序就可以通过该数组变量访问数组对象。
Java语言不允许直接访问堆内存中的对象,因此无法直接访问堆内存中的数组对象,程序将通过数组引用变量来访问数组对象。
Java语言避免直接访问堆内存可以使程序更加健壮,如果程序直接访问并修改堆内存中的数据,可能破坏内存的数据完整性,从而导致程序Crash。
无论哪种类型的数组,其数组元素其实相当于一个普通变量。
下面程序师范了将数组元素和普通变量相互赋值的情形:
class Cat{String name;double height;public Cat(String name, double height){this.name = name;this.height = height;}public void info(){System.out.println("name:" + name + ", height:" + height);}
}public class TestArray {public static void main(String[] args) {int[] a = new int[5];for(int i=0; i<a.length; i++){a[i] = ++i;}int x = a[0];int y = 99;a[4] = 99;Cat[] cats = new Cat[2];cats[0] = new Cat("咪咪", 10.0);cats[1] = new Cat("卡卡", 12.2);Cat c1 = cats[0];Cat c2 = new Cat("豆豆", 11.1);cats[1] = c2;}
}
内存分析:
6. 没有多维数组
所谓多维数组,其实只是数组元素元素依然是数组的数组,1维数组的数组元素的基本类型或者引用类型,2维数组的数组元素是1维数组,3维数组的数组元素是2维数组...N维数组的数组元素是N-1维数组。
Java允许将多维数组当成1维数组来处理,初始化多维数组时可以先初始化最左边的维数,此时该数组的每个数组元素都相当于一个数组引用变量,这些数组还需要进一步初始化。
如下程序示范了多维数组的用法:
public static void main(String[] args) {int[][] a;a = new int[4][];// 把a当成一维数组,遍历a数组的每个数组元素for(int i=0; i<a.length; i++){System.out.println(a[i]); // 输出都为null}a[0] = new int[2];a[0][1] = 2;for(int i=0; i<a[0].length; i++){System.out.println(a[0][i]); // 输出0和2}
}
内存分析:
说明:一般我们认为通过数组的length属性可以获取数组的长度,其实这个说法不够准确,例如数组a,它是一个传统的“二维数组”,它的长度好像定义不是很明确,其实,数组的长度指的是数组所分配的连续内存空间的长度,所以说a数组的长度为4.
我们用一个“极端”的程序来更好的理解数组在内存中的分配机制:
public static void main(String[] args) {Object[] objArr1 = new Object[3];objArr1[1] = new Object[2];Object[] objArr2 = (Object[]) objArr1[1];objArr2[1] = new Object[3];Object[] objArr3 = (Object[]) objArr2[1];objArr3[1] = new int[5];int[] iArr = (int[]) objArr3[1];for(int i=0; i<iArr.length; i++){iArr[i] = ++i;}
}
内存分析:
此时的objArr1不再是一个简单的一维数组,它是一个四维数组。
最后我们执行如下语句:
System.out.println(((int[])((Object[])((Object[])objArr1[1])[1])[1])[2]);
通过以上内存分析不难得出结果为3.
通过上面的分析不难得出,多维数组的本质仍然是一维数组。
因为Java是强类型语言,所以上诉代码需要多次强制类型转化,如果用弱类型语言实现会简单很多,比如用JavaScript实现:
<script type="text/javascript">var objArr1 = [];objArr1[1] = [];var objArr2 = objArr1[1];objArr2[1] = [];var objArr3 = objArr2[1];objArr3[1] = [];var iArr = objArr3[1];for(var i=0; i<5; i++){iArr[i] = i;}document.write(objArr1[1][1][1][2]);
</script>
Java数组初始化的内存分配相关推荐
- JAVA中堆栈和内存分配原理
JAVA中堆栈和内存分配原理 1.栈.堆 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...
- java数组 初始化_用Java初始化数组
java数组 初始化 具有使用C或FORTRAN等语言进行编程的经验的人熟悉数组的概念. 它们基本上是一个连续的内存块,每个位置都是某种类型:整数,浮点数或您所拥有的. Java中的情况与此类似,但有 ...
- java数组初始化的方式_java数组初始化方式
在使用一个新的数组之前,要先对其中的数值进行设置,也就是我们常说的初始化工作.因为数组有长度和内容的区分,所以常见的两种初始化方法是动态和静态,另外一种就是默认初始化.下面我们对数组的初始化概念进行理 ...
- java数组中的内存特征
java数组中的内存特征(笔记) 1,基本数据类型创建的变量,存储在栈内存中,占用一块内存,是方法中内部的局部变量,数据量比较小,一种临时的使用. 2,引用类型的数据创建的变量,存储在堆内存上,栈内存 ...
- 二维数组及其二维数组的动态内存分配
本文为大一时所写的文章(2017/4/9),文笔还很生疏,在很多问题上认识不深,算是在学校的微信公众号上的一个编程探究模块上的投稿,本人当时也参与了本模块的维护和管理.补档. 今天我们来聊聊二维数组及 ...
- 二维数组及其动态内存分配
一.二维数组的基本概念 1.1 二维数组的内存映像 从内存角度看,二维数组和一维数组一样,在内存中都是连续分布的多个内存单元,并没有本质差别,只是内存的管理方式不一样,如下图所示 一维数组int a[ ...
- java数组初始化赋值_Java数组的三种初始化方式
Java语言中数组必须先初始化,然后才可以使用.所谓初始化就是为数组的数组元素分配内存空间,并为每个数组元素附初始值. 注意:数组完成初始化后,内存空间中针对该数组的各个元素就有个一个默认值: 基本数 ...
- Java数组初始化长度
巴拉巴拉小魔仙:肯定是要先声明数组长度,不然系统不会为他分配内存空间. Java中的数组是定长的,比如int[] a ={}; 定义出来的数组a 长度为0,已经是定长了,之后再给它赋值是不可以的,因为 ...
- java 数组 初始化 个数_Java中数组的初始化
一.什么是初始化 在Java程序开发中,使用数组之前都会对其进行初始化,这是因为数组是引用类型,声明数组只是声明一个引用类型的变量,并不是数组对象本身,只要让数组变量指向有效的数组对象,程序中就可使用 ...
最新文章
- 对称性破缺衰变与分类
- Linux系统下提升进程优先级的办法
- wxWidgets:wxBusyInfo类用法
- 2019蓝桥杯省赛---java---B---1(组队)
- (转)淘淘商城系列——服务调用测试
- java 蓝牙指定连接失败_java – Android蓝牙连接 – 服务发现失败
- caffe 利用python绘制loss曲线以及accuracy曲线
- a标签的CSS伪类,点击后变色
- Storyboard使用心得
- 多线程java_敞开心扉,一起聊聊Java多线程
- html怎么添加自动关机,电脑自动关机设置方法大全
- 非正式第十三届蓝桥杯大赛
- mysql编写1到n的奇数和_编写程序。输入任意整数n,计算1到n的奇数和
- 说几句得罪人的大实话
- 基于B/S模式的学生选课系
- Word无法打开文件,因为文件格式与文件扩展名不匹配
- android键盘管理,用鼠标键盘控制你的Android手机完整图文教程
- tex模版wins版本在mac中字体不对应问题解决方案
- 在 Windows 10 中保存和恢复桌面图标位置的 2 个免费工具
- 雅虎口碑将关闭站长天下服务平台