在网上做题,做错了一道关于值传递和引用传递的问题,如下:
class Value{
public int i=15;
}
public class Test{
public static void main(String argv[]){
Test t=new Test( );
t.first( );
}
public void first( ){
int i=5;
Value v=new Value( );
v.i=25;
second(v,i);
System.out.println(v.i);
}
public void second(Value v,int i){
i = 0;
v.i = 20;
Value val = new Value( );
v = val;
System.out.println(v.i+" "+i);
}
}
答案:15 0 20
估计好多人都以为是15 0 15吧,但是是错误的。从此文中(https://www.cdsy.xyz/computer/programme/java/230131/cd39968.html)摘抄了一段话,感觉说的很到位:
Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值.
如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。
将上述话用于解决该题再合适不过了,
我将v前后的hashcode打印了一下,印证了上述观点:
调用second方法前后v的地址未变,而在second方法中在val赋值v之后,v的地址有变化,并没有影响调用之后v的地址,说明second方法中的v只是first方法中v的副本。
class Value {
public int i = 15;
}
public class TestValue {
public static void main(String argv[]) {
TestValue t = new TestValue();
t.first();
}
public void first() {
int i = 5;
Value v = new Value();
v.i = 25;
System.out.println("first方法调用second方法前v的地址:" + v.hashCode());//122883338
second(v, i);
System.out.println("first方法调用second方法后v的地址:" + v.hashCode());//122883338
System.out.println(v.i);
}
public void second(Value v, int i) {
System.out.println("second方法中v的地址" + v.hashCode());//122883338
i = 0;
v.i = 20;
Value val = new Value();
v = val;
System.out.println("second方法中val的地址" + val.hashCode());//666641942
System.out.println("second方法中v改变赋值之后的地址" + v.hashCode());//666641942
System.out.println(v.i + " " + i);
}
}