JAVA 是值传递还是引用传递 傻傻分不清楚?
-
值传递:在调用函数的时候,把真实的实际参数传递给形式参数的时候,传递给函数的并不是实际参数本身,而是对实际参数的拷贝。所以在函数里面操作参数改变的是形参的数值,而实参的值并不会受到影响。
-
引用传递:在调用函数的时候,把真实的实际参数传递给形式参数的时候,传递给函数的就是实际参数本身,在函数里面操作参数就是对实际参数的改变。
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a);
System.out.println("b = " + b);
}
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
System.out.println("num1 = " + num1);// num1=10
System.out.println("num2 = " + num2);// num2=20
}
对java而言,它只有值传递。
但对于下面两个引用类型的参数传递,有些人会感到疑惑?
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5 };
System.out.println(arr[0]);
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] array) {
array[0] = 0;
}
//结果为 arr={0,2,3,4,5} ,不是说好不变吗,怎么又变了?
public static void swap(Student x, Student y) {
Student temp = x;
x = y;
y = temp;
System.out.println("x:" + x.getName());
System.out.println("y:" + y.getName());
//System.out.println(x.hashCode());//2222222
//System.out.println(y.hashCode());//1111111
// y.setName("111111aaaaaa");
}
public static void main(String[] args) {
Student s1=new Student("gg1");
Student s2=new Student("gg2");
// System.out.println(s1.hashCode());//1111111
// System.out.println(s2.hashCode());//2222222
swap(s1,s2);
System.out.println("s1:" + s1.getName());
System.out.println("s2:" + s2.getName());
}
//main 运行结果如下 s1和s2引用对象没有发生改变
x:gg2
y:gg1
s1:gg1
s2:gg2
//但如果把 10行加入其中 运行结果为 s1和s2引用对象的属性name确实发生了改变
x:gg2
y:gg1
s1:111111aaaaaa
s2:gg2
通过函数调用,数组内容的改变和对象属性的改变,难道不是代表是引用传递吗,把实际参数地址传给了形参吗?
实际上,还是值传递。只是大家对Java中的基本类型和引用类型理解还是不深。
- 基本数据类型的值传递 好理解,实参的值放到了栈中,在函数调用的时候,如定义的swap(int a,int b)函数,输入x,y。使用swap(x,y)。a拷贝了x,是x的一个副本,后面在函数内对a的修改并不会对x进行影响。
- 引用数据类型的值传递过程是:例如上面定义一个swap(Student x, Student y),输入s1,s2。调用swap(s1,s2)。你们看它们的hasCode就知道了,实际上 ,s1,s2的地址丝毫没变。引用对象拷贝复制的是在栈中的一个地址。这个地址是标记引用对象在堆中对象内容(属性)。所以,对于引用类型而言,值传递 拷贝复制地址使得形参和实参的地址一样,该地址指向的堆内容一样。如果形参改变了指向堆内容信息(类的属性)如 y.setName(“111111aaaaaa”),实参地址指向堆内容信息的内容也会发生改变
总结
- 对于基本类型值传递是 对数值的拷贝 ,形参改变不影响实参。
- 对于引用数据类型值传递的是引用对象地址的拷贝,但不能让一个引用对象引用新的另一个引用对象。如上,s1,s2 在进行swap函数的前后,s1和s2的地址不变。 但能通过值传递改变 一个引用对象的内容(属性)如上 arr[]={1,2,3,4,5} 进行change函数后 实际变成了arr=[0,2,3,4,5]。 s1.name 通过swap 变成 111111aaaaaa。