最近偶然看到一篇博客,你真的理解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指向的值。
上面例子中的流程可以参考下图:
再看一个类似的例子:
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参数传递时,是值传递,还是引用传递呢?