从字节码看为什么说java都是值传递

2018-05-12  本文已影响4人  上重楼

先上源码

public class TestRef {

    public int id = 1;


    public static void main(String[] args) {
        int a = 10;
        String b = "a";
        TestRef c = new TestRef();

        change(a);
        change(b);
        change(c);
        changeRef(c);


    }

    public static void change(int a) {
        a = 20;
    }

    public static void change(String b) {
        b = "c";
    }

    public static void change(TestRef c) {
        c = new TestRef();
    }


    public static void changeRef(TestRef c) {
        c.id = 10;
    }
}

再上字节码:

public class TestRef {
  public int id;

  public TestRef();
    Code:
       0: aload_0                            //将this载入栈顶
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V 
       4: aload_0                           //再次将this载入栈顶,因为上面那行invokespecial已经消耗掉第一行的this去实例化对象了
       5: iconst_1                          //将常量值1推入栈顶
       6: putfield      #2                  // Field id:I  //设置偏移4那行推入的this的#2变量的值为偏移5那行所推入的值
       9: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: istore_1
       3: ldc           #3                  // String a
       5: astore_2
       6: new           #4                  // class TestRef
       9: dup
      10: invokespecial #5                  // Method "<init>":()V
      13: astore_3
      14: iload_1
      15: invokestatic  #6                  // Method change:(I)V
      18: aload_2
      19: invokestatic  #7                  // Method change:(Ljava/lang/String;)V
      22: aload_3
      23: invokestatic  #8                  // Method change:(LTestRef;)V
      26: aload_3
      27: invokestatic  #9                  // Method changeRef:(LTestRef;)V
      30: return

  public static void change(int);
    Code:
       0: bipush        20
       2: istore_0
       3: return

  public static void change(java.lang.String);
    Code:
       0: ldc           #10                 // String c
       2: astore_0
       3: return

  public static void change(TestRef);
    Code:
       0: new           #4                  // class TestRef
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_0
       8: return

  public static void changeRef(TestRef);
    Code:
       0: aload_0        //将参数载入栈
       1: bipush        10    //推入一个10
       3: putfield      #2                  // Field id:I  //设置参数的#2实例变量的值为10
       6: return
}

3个change(T)方法都是错误的使用例子,从字节码可以看到基本都是在操作方法自身的局部变量表,方法的参数都是一个对象引用(或者说指向对象内容的指针副本) 修改也只是将指针的值改变,而非指针指向的值

changeRef方法第一行就是 aload_0这个和构造函数第一行一样,都是将this载入栈顶
而this是一个指向对象的引用(指针)。
在main方法偏移26那行,aload_3 是将局部变量表slot 3 的的对象引用复制到栈顶,这样从旁证明了,java传递对象的时候传递的是对象的引用的副本 对象的引用是4个字节(操作数栈和局部变量表 都是一个单位等于4个字节 基本类型除了 double long之外其他都是一个单位)这也从旁佐证 方法调用传递的是对象引用副本

上一篇 下一篇

猜你喜欢

热点阅读