一、数组
定义
和 C 语言一样,Java 中的数组是一块连续的内存,里面可以存放相同类型的变量。
创建数组
在 Java 中数组的创建有三种方式:
1) Java 中 [ ] 符号,可以写在变量名前面(写在后面也行)。而这样我们可以更好的理解,上述数组的类型是 int[ ]
2) 数组类型中的 [ ]内不能写数值 ,也就是int[ ] array4 =new int[ 5 ]{1,2,3,4,5};就是错误的
3) 静态初始化的时候,数组元素个数和初始化数据的格式是一致的
如下:
细节理解:
数组的使用(与c大致)
注意:
数组遍历
循环遍历
int[] arr = {1, 2, 3};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
用 for-each 遍历
int[] arr = {1, 2, 3};
for (int x : arr) {
System.out.println(x);
}
补充
二、数组作为方法的参数
认识 JVM 内存区域划分
一个 Java 文件的执行需要先通过编译变成字节码文件,字节码文件再通过 Java 虚拟机运行,JVM 本质其实就是一个用 C/C++ 代码实现的软件,它的内存被划分五块为程序计数器、Java 虚拟机栈、本地方法栈、堆、方法区。
程序计数器:是一个很小的空间,保存下一条执行的指令地址
Java 虚拟机栈:这就是我们平常说的栈,它重点是存储局部变量(如创建的数组的存储地址的引用就存在这里)
本地方法栈:本地方法栈与虚拟机栈的作用类似,只不过保存的内容是 Native 方法( Java 中调用的一些 C++ 实现的函数)的局部变量
堆:这就是我们平常说的堆,是 JVM 所管理的最大的内存区,使用 new 创建的对象都是在堆上保存
方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据(方法编译出的字节码就是保存在这里)
运行时常量池:这个是方法区的一部分用来存放字面量(字符串常量)与符号引用(注意:从 JDK 1.8 开始,运行时常量池在堆上)
理解Java中的栈和堆:
局部变量开辟在栈中,固定数组在函数体内的声明也在栈中,但是动态数组(相当于malloc)以及数组中的变量开辟在堆中。
对于以下的代码的空间分析:
数组传值和传引用
我们可以说 array2 这个引用指向 array1 这个引用吗?不能!这其实是表述有误!
引用不能说指向引用,引用只能说指向另一个引用所指的对象。故我们应该理解成:array2 这个引用指向了 array1 这个引用所指向的对象
-> 引用类型本质上只是存了一个地址 Java
-> 将数组设定成引用类型,这样后续进行数组参数传参,其实只是将数组的地址传到函数的形参中。这样可以避免对整个数组进行拷贝,减小开销
-> Java中的引用类型有:String、数组、类、接口、枚举、抽象类
认识 null
null 在 Java 中表示空引用,是一个无效的引用,因此不能对这个内存进行任何读写操作
Java 中并没有约定 null 和 0 号地址的内存有任何联系(这和 C 语言中的指针赋值为 null 就是表示0号地址不同)
代码:
int[ ] array = null;
意思就是 array 这个引用不指向任何对象。这其实和 C 语言里的空指针类似,当我们不道该数组初始化为多少时,就可以赋值为 null
三、二维数组
二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组
创建数组
通过类比一维数组创建的方式,二维数组也有三种方式
此外还有一种定义
int[ ][ ] array = new int[2][ ];
Java 二维数组省略列的”只创建外围方式“,我们成为“不规则二维数组”。
注意空指针异常 :但是这样如果不初始化,打印时会出现异常,因为没有列的话,相当于该二维数组的两个元素都为 null(默认值)。
因此打印前要进行初始化,如
存储结构
java中的存储如下:
再例如:(上述代码为例)
代码验证
可以通过 array.length 验证长度为2的结论,并且再用这个方式验证每个元素又是一个一维数组的结论。
int[][] array = {{1, 2, 3,4}, {1,2,3,4,5, 6,7}};
System.out.println(array.length);//打印结果为:2
System.out.println(array[0].length);//4
System.out.println(array[1].length);//7