zoukankan      html  css  js  c++  java
  • 【Java基础】基本类型的包装类作为参数传递是值传递还是引用传递

    突然想到这个问题,然后做了下实验,下面以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)这个新产生的对象,所以最后和值传递的效果一样,不会改变调用该方法的参数的值。

  • 相关阅读:
    Python----定义
    [转载]Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
    彻底明白IP地址——计算相关地址
    [转载] 教你如何迅速秒杀掉:99%的海量数据处理面试题
    [转载]从B 树、B+ 树、B* 树谈到R 树
    [转载]Java抽象类和接口的学习
    [转载]字符串匹配的Boyer-Moore算法
    [转载]字符串匹配的KMP算法
    [转载]孤儿进程与僵尸进程[总结]
    [转载]Huffman编码压缩算法
  • 原文地址:https://www.cnblogs.com/gslyyq/p/4950734.html
Copyright © 2011-2022 走看看