一、引用
int[] a = new int[10];
int[] b;
b = a;
让数组b直接指向数组a(即b = a;),这样做的目的是为了提高程序运行的效率。
试想一下,假如数组中有上万个元素,在拷贝数组时,如果将数组a的所有元素都一一拷贝至数组b,时间开销很大,有时候也不是必需的。
所以,在Java语言中, b = a(a和b都是引用名)的含义就是将a起个别名"b"。
之后,a和b其实就是指向的是同一个对象。
在Java中,这种给变量取别名的机制称之为引用(reference)。
抽象的概念都源于具体的表象。
一个程序若想运行,必须驻入内存,而在内存中必然有其存储地址,通过这些内存地址,就可以找到我们想的数据。
这些内存地址通常都很长(具体长度取决于JVM的类型),因为不容易记住,所以就给这些地址取个名称,这就是引用变量,这些引用变量存储在一块名叫 “栈内存” 的区域。
那么所谓“引用”,就是Java对象在堆内存的地址赋给了多个“栈内存”的变量。
由于Java禁止用户直接操作“堆整型、浮点型、布尔型等基本数据类内存”中对象的地址,所以只能用这些“栈内存”的多个引用名来间接操作它们对应的“堆内存”数据。
所以,Java中的“引用”更类似于C/C++中的“指针”概念,所不同的是,C/C++中的“指针”可以被用户直接修改,而在Java中对内存的直接修改是被屏蔽的。
二、数组引用传递
在Java中,所有对象都是通过引用进行操作的。 而数组也是一种对象。当将数组作为参数传递给方法时,传递的实际上就是该数组对象的引用在方法中对数组的所有操作,都会映射到原数组中,这一点也是Java面向对象的一个重要特点。
所谓的数组引用传递,就是将一块数组的堆内存空间交由多个栈内存所指向。
这包括了方法通过参数列表接收数组和方法计算完毕后返回数组等两种情况,但不管数组操作形式如何改变,最终都属于引用传递。
请注意,除了对象有这种特性外,整型、浮点型、布尔型等基本数据类型都不具备该特性。
public class ArrRef {
public static void changeReferValue(int a,int[]myArr) {
a+=1; //将参数a加1
myArr[0]=0; //将数组的三个元素全部置0
myArr[1]=0;
myArr[2]=0;
}
//打印数组元素
public static void printArr(int[]arr) {
for(int i:arr) {
System.out.print(i+"");
}
System.out.println(); //输出一个换行符
}
//打印结果
public static void print(int in,int[]arr) {
System.out.println("in:"+in);
System.out.print("arr:");
printArr(arr);
}
public static void main(String[] args) {
int in=10;
int arr[]={1,2,3,4,5};
System.out.println("----调用changeReferValue方法之前--------");
print(in,arr);
changeReferValue(in,arr);
System.out.println("----调用changeReferValue方法之后--------");
print(in,arr);
}
}
【结果】
【范例分析】
因为数组是对象,所以在changeReferValue方法的参数列表中,最后一个参数传递形式为 “传引用”。
换句话说,main方法中实参arr和changeReferValue方法中的形参myAr指向同一块内存空间。
因此,在changeReferValue方法中,对形参arr所指向的数组数据的任何修改,都会同步影响到main方法中的实参arr所指向的数组数据(myAr和arr本质上就上一块内存区域)。
在changeReferValue方法中,由于对于整型形参a和实参in之间是 “传值” 关系。在实参in将值赋值给形参a后,形参和实参二者之间再没有任何关联,所以在方法changeReferValue中对a的+1操作,并没有影响实参in的值,在本质上,形参a和实参in所指向的完全是不同的内存空间。