Java参数传递方式---值传递还是引用传递

时间:2022-09-14 21:24:08

最近偶然看到一篇博客,你真的理解Java的按引用传递吗?

然后,看了一下文中的几个例子,确实一开始,自己做错了,虽然用Java已经有四年时间了,但是还是发现自己没有彻底理解清楚,到底是值传递还是引用传递。

首先,明确一下,什么是值传递,什么是引用传递。

Java中的值传递:Java中的基本数据类型,传递给方法形参时,是直接将值传递过去的,准确的说,应该是将值copy了一份,传递给了形参。

大家经常说的Java中的引用传递:除了基本数据类型外,Java的参数传递方式,是将实参的地址值,copy了一份,传递给了形参,所以其实这里所说的引用传递,也可以理解成值传递(实参地址值的传递)。

关于这些基本类型的参数,和引用类型数据的存放位置,可以参考这篇博客:java中的基本数据类型存放位置

理解了上面内容后,再看这些例子,就不难理解了

如下代码:

public class Test1 { 
    String a = "123"; 
    public static void change(Test1 test) { 
        test.a="abc"; 
    }
    public static void main(String[] args) { 
        Test1 test1=new Test1(); 
        System.out.println(test1.a); 
        change(test1); 
        System.out.println(test1.a); 
    } 
}

结果输出123 abc

因为将实参test1传递到change方法后,形参test在change方法栈中,也有了一个位置,它们都指向存储在堆内存中的实际对象的值,所以当在change方法里修改test指向的对象的值后,在堆中的数据值已经被改变,所以最后在方法外打印时,是修改后的值。

第二个例子,

public class Test2{
    public static void main(String[] args) {
        String str = "123";
        System.out.println(str);
        change(str);
        System.out.println(str);
    }
    public static void change(String str1){
        str1 = "abc";
    }
}

结果输出123 123

因为在change方法里,形参str1在栈里也有一位存储位置,和实参str记录的地址值是一样的,都指向存在在堆中的值“123”,当执行str1 = “abc”;后,形参指向了堆中的“abc”, 即已经和实参的指向不一样了,但是这并没有影响实参str的指向,所以,在change方法外,打印时,仍然是str指向的值。

上面例子中的流程可以参考下图:
Java参数传递方式---值传递还是引用传递

再看一个类似的例子:

public class Test3{
    public static void main(String[] args) {
        Object o = new Object();
        System.out.println(o);
        change(o);
        System.out.println(o);
    }
    public static void change(Object obj){
        obj = null;
    }
}

结果打印的o 仍然有值,

因为实参o传递到方法后,形参obj拥有了一个实参o在栈中的地址备份,和实参o记录的地址值是一样的,它们共同指向存在堆中的值,当执行到
obj = null时,形参已经指向了null,但是没有改变实参o的指向,所以最后打印实参o时,仍然有值。

最后,你觉得Java参数传递时,是值传递,还是引用传递呢?

参考:JAVA中值传递和引用传递的三种情况