1. 一维数组内存分析
1.1 Java虚拟机的内存划分
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
- Java虚拟机最先接触的就是字节码文件class file
- 有了类加载文件以后 类加载器子系统就把class文件加载到内存了 在反射的时候会讲
- 分配到内存区域 - 运行时数据区
- 运行数据区分为几个部分?
- 程序计数器
- 本地方法栈
- 虚拟机栈
- 方法区
- 堆
- 运行数据区分为几个部分?
区域名称 | 作用 |
---|---|
虚拟机栈 | 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放。 |
堆内存 | 存储对象(包括数组对象),new来创建的,都存储在堆内存。 |
方法区 | 存储已被虚拟机加载的类信息、常量、(静态变量)、即时编译器编译后的代码等数据。 |
本地方法栈 | 当程序中调用了native的本地方法时,本地方法执行期间的内存区域 |
程序计数器 | 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
与目前数组相关的内存结构,比如int[] arr = new int[] {1,2,3}
- 虚拟机栈:用于存放方法中声明的变量,比如:arr
- 堆:用于存放数组的实体:即数组中所有的元素,比如:{1,2,3}
- 第一行代码
- 先在栈中存放arr1,在堆内存空间开辟一个连续4个的空间,并且对外只暴露首地址值 0x12ab
- 栈中arr1变量的值放的是首地址值 0x12ab,此时就构成了一个指针,指向堆内存中这个数组的首位置
- 给int数组默认值 0,0,0,0
- 第二三行,给下标0和2的数组元素赋值
- 第四行代码
- 先在栈中存放arr2,在堆内存空间开辟一个连续2个的空间,并且对外只暴露首地址值 0xaabb
- 栈中arr2变量的值放的是首地址值 0xaabb,此时就构成了一个指针,指向堆内存中这个数组的首位置
- 给String数组默认值 null,null
- 第五行代码
- 暂且放到后面讲 涉及常量池
- 第六行代码
- 重新开辟空间,长度为3的连续空间0x12cd
- arr2变量存放的值为0x12cd,原来的不要了
- 给String数组默认值 null,null,null
- 堆空间中0xaabb就成了垃圾,被GC回收
- 整个main方法结束了,弹栈,里面的arr1和arr2也不存在了,栈桢也不存在,堆内存的内容也不存在,垃圾回收
将arr的地址值赋给arr1
只要出现new
,就会在堆空间中开辟新的内存,否则不会
一维数组的练习,见Gitee
2.二维数组
String[][] grade = new String[][]{{"段誉","令狐冲"},{"张三丰","周芷若"},{"赵敏","张无忌","韦小宝","杨过"}};
2.1 声明与初始化
2.1.1 静态初始化
int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
定义一个名称为arr的二维数组,二维数组中有三个一维数组
- 每一个一维数组中具体元素也都已初始化
- 第一个一维数组 arr[0] = {3,8,2};
- 第二个一维数组 arr[1] = {2,7};
- 第三个一维数组 arr[2] = {9,0,1,6};
- 第三个一维数组的长度表示方式:arr[2].length;
- 注意特殊写法情况:int[] x,y[]; x是一维数组,y是二维数组。
int[][] arr = {{1,2,3},{4,5,6},{7,8,9,10}};//声明与初始化必须在一句完成
int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
int[][] arr;
arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
arr = new int[3][3]{{1,2,3},{4,5,6},{7,8,9,10}};//错误,静态初始化右边new 数据类型[][]中不能写数字
2.1.2 动态初始化
2.1.2.1 格式1:规则二维表:每一行的列数是相同的
int[][] arr = new int[3][2];
- 定义了名称为arr的二维数组
- 二维数组中有3个一维数组
- 每一个一维数组中有2个元素
- 一维数组的名称分别为arr[0], arr[1], arr[2]
- 给第一个一维数组1脚标位赋值为78写法是:arr[0][1] = 78;
2.1.2.2 格式2:不规则:每一行的列数不一样
(1)先确定总行数
元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][];
(2)再确定每一行的列数,创建每一行的一维数组
二维数组名[行下标] = new 元素的数据类型[该行的总列数];
int[][] arr = new int[3][];
- 二维数组中有3个一维数组。
- 每个一维数组都是默认初始化值null (注意:区别于格式1)
- 可以对这个三个一维数组分别进行初始化:arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];
- 注:int[][]arr = new int[][3]; //非法
2.1.3 数组元素的默认初始化值
动态初始化方式1
int[][] arr = new int[3][4]
外层元素:默认存储地址值
内层元素:默认与一维数组元素的不同类型的默认值规定相同
- int数组元素默认初始值:0
- 浮点型数组元素默认初始值:0.0
- char数组元素默认初始值:0
- boolean数组元素默认初始值:false
- 引用型数组元素默认初始值:null
int[][] arr = new int[3][2];
// 外层元素默认值:
System.out.println(arr[0]); // 地址值,只想了一个一维数组
System.out.println(arr[1]);
// 内层元素默认值:
System.out.println(arr[0][0]); // 0 因为是int类型
-----------------------------------------------------------------
boolean[][] arr1 = new boolean[3][4];
// 外层元素默认值:
System.out.println(arr1[0]); // 地址值,只想了一个一维数组
// 内层元素默认值:
System.out.println(arr1[0][1]); // false
-----------------------------------------------------------------
String[][] arr2 = new String[4][2];
// 外层元素默认值:
System.out.println(arr2[0]); // 地址值,只想了一个一维数组
// 内层元素默认值:
System.out.println(arr2[0][1]); // null;
-----------------------------------------------------------------
动态初始化方式2
int[][] arr = new int[3][]
外层元素:默认存储null,因为数组是引用类型
内层元素:空指针异常
int[][] arr = new int[4][];
// 外层元素默认值:
System.out.println(arr[0]); // null
// 内层元素默认值:
System.out.println(arr[0][0]); // 报错空指针;没有数组
2.2 二维数组内存解析
- arr1指向一个一维数组,地址值为0xaabb,在arr1变量内保存
- arr2[2][2]里面没有数组,所以报错空指针
- arr1第二个[]写了就是地址值,没写就是null