数据类型[] 数组名称 = new 数据类型 [长度] { 初始化数据 };
示例:int[] arr = new int[3]{1, 2, 3};
数据类型[] 数组名称 = { 初始化数据 };
示例:int[] arr = {1, 2, 3};
我们知道C++中数组下标越界读写是一个未定义行为,结果不可预期,那Java中是这样的吗?
请看代码:
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
at Test.main(Test.java:4)
可以看出程序抛出了java.lang.ArrayIndexOutOfBoundsException
异常,这就涉及到Java的异常处理机制,所以使用数组一定要下标谨防越界。
int[] arr = {1, 2, 3};
for (int x : arr) {
System.out.println(x);
}
// 执行结果
1
2
3
这种写法类似于C++11
中范围for的用法,区别在于C++中使用了auto
自动类型,而Java中写明了原数据类型。
因此直观的、良好的习惯值得被弘扬,Java 如此设计在其他语言中得到了传承。
请看代码:
public static void main(String[] args) {
int num = 0;
func(num);
System.out.println("num = " + num);
}
public static void func(int x) {
x = 10; //在函数内修改
System.out.println("x = " + x);
}
执行结果:x = 10 num = 0
public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}
执行结果:a[0] = 10 arr[0] = 10
这让我们联想到C++中参数的传递方式之一的引用传参(&),而Java中很明显对于内置类型的传参与C++一致,但数组类型就有所不同了,从上述案例可以看出,在函数内部修改数组内容, 函数外部也发生改变。
所以:Java中对函数传递数组类型时,相当于按照引用传参。
针对于:
int[] arr = new int[]{1, 2, 3}
- 当我们创建
new int[]{1, 2, 3}
的时候,相当于创建了一块内存空间保存三个int
类型的数据。- 而
int[] arr
这一语句创建了一个int[]
类型变量,这个变量是一个引用类型,其中保存了一个整数(数组的起始内存地址),赋值给它相当于使它获得了操作句柄。- 之后进行传参,在函数中执行如
int[] a = arr
的语句,使a
数组也获取了与arr
一样的这三个类型数据的地址。- 所以对
a
数组的修改就是针对arr
的修改,本质上就是根据地址来获取/修改数据。
说到引用就要与内存联系起来,C++中我们知道引用的底层是通过指针实现的,而Java中就涉及了JVM(Java Virtual Machine)内存划分的知识。
我们可以从操作系统的用户地址空间知识进行引申,内存被分为很多个区域,每个区域存放着不同的数据。
PC Register
):只是一个很小的空间, 保存下一条执行的指令的地址。JVM Stack
):重点是存储局部变量表(当然也有其他信息). 我们刚才创建的 int[] arr 这样的存储地址的引用就是在这里保存。Native Method Stack
):本地方法栈与虚拟机栈的作用类似,只不过保存的内容是Native方法的局部变量。但在有些版本的 JVM 实现中(例如HotSpot),本地方法栈和虚拟机栈是一起的。Heap
):JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} )。Method Area
):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法编译出的的字节码就是保存在这个区域。Runtime Constant Pool
):是方法区的一部分,存放字面量与符号引用。Native 方法:
JVM 是一个基于 C++ 实现的程序。在 Java 程序执行过程中,本质上也需要调用 C++ 提供的一些函数进行和操作系统底层进行一些交互。因此在 Java 开发中也会调用到一些 C++ 实现的函数。
这里的 Native 方法就是指这些C++
实现的, 再由Java
来调用的函数。
所以代入一下案例,引用类型int[]
的a
与arr
数组都是JVM栈数据,new int[]{1,2,3}
是堆区数据,a与arr都存放着此堆区数据的地址。