在网上做题,做错了一道关于值传递和引用传递的问题,如下:
- 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);
- }
- }
-