突然想到这个问题,然后做了下实验,下面以Integer来讲解,其他的忽略:
import java.util.Iterator; /** * Created by lili on 15/9/24. */ public class TestNew { public static void main(String args[]){ Integer i1 = 10; Integer i2 = 20; System.out.println(i1 + " " + i2); change(i1,i2); System.out.println(i1 + " " + i2); String s1 = new String("s1"); String s2 = new String("s2"); System.out.println(s1 + " " + s2); change(s1, s2); System.out.println(s1 + " " + s2); StringBuilder sb1 = new StringBuilder("sb1"); StringBuilder sb2 = new StringBuilder("sb2"); System.out.println(sb1 + " " + sb2); change(sb1,sb2); System.out.println(sb1 + " " + sb2); } public static void change(Integer i1, Integer i2){ i1 = 100; i2 = 200; } public static void change(String i1, String i2){ i1 = "ii1"; i2 = "i22"; } public static void change(StringBuilder i1, StringBuilder i2){ i1.append("sbsbsb1"); i2.append("sbsbsb2"); } }
运行结果:
10 20
10 20
s1 s2
s1 s2
sb1 sb2
sb1sbsbsb1 sb2sbsbsb2
Process finished with exit code 0
事实证明,只有StringBuilder是引用传递,其他的还是值传递。
按照常理,应该传递的是对象的地址,难道这里是因为做了自动装箱和拆箱,编译器帮你做了这个导致最后是值传递了?
带着这个问题首先去看了class文件的反编译代码:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // public class TestNew { public TestNew() { } public static void main(String[] var0) { Integer var1 = Integer.valueOf(10); Integer var2 = Integer.valueOf(20); System.out.println(var1 + " " + var2); change(var1, var2); System.out.println(var1 + " " + var2); String var3 = new String("s1"); String var4 = new String("s2"); System.out.println(var3 + " " + var4); change(var3, var4); System.out.println(var3 + " " + var4); StringBuilder var5 = new StringBuilder("sb1"); StringBuilder var6 = new StringBuilder("sb2"); System.out.println(var5 + " " + var6); change(var5, var6); System.out.println(var5 + " " + var6); } public static void change(Integer var0, Integer var1) { var0 = Integer.valueOf(100); var1 = Integer.valueOf(200); } public static void change(String var0, String var1) { var0 = "ii1"; var1 = "i22"; } public static void change(StringBuilder var0, StringBuilder var1) { var0.append("sbsbsb1"); var1.append("sbsbsb2"); } }
源代码显示并没有做值传递的优化,因为如果做了,应该change中的参数会改为int,这样一来Integer对象会自动拆装为int进行值传递,一种自动装卸拆箱的代码示例如下:
Integer integer = 11; integer += 9; /* Integer integer = Integer.valueOf(11);//自动装箱 integer = Integer.valueOf((integer.intValue() + 9));//自动拆箱再装箱 */
那究竟是什么原因呢?
带着这个问题,对程序进行了debug,看看传递的是否是对象地址。
进入change方法后,看地址的变化
发现传入的是地址值,change参数的i1和i2的对象指向Integer@417和Integer@418,说明指向和传入参数的同一个对象,传入的是地址。
接着执行方法change程序:
执行改变i1的值时,此时i1指向的对象改为了Integer@427,至此可以充分说明不是自动装箱和拆箱的问题了,但是究其原因,我的理解还是和这个相关,因为执行到这一步的时候是i1 = 100;但是具体编译器优化后做了自动装箱处理,var0 = Integer.valueOf(100);所以i1指向了Integer.valueOf(100)这个新产生的对象,所以最后和值传递的效果一样,不会改变调用该方法的参数的值。