您的位置 首页 java

值传递与引用传递

值传递

         int n = 1;
        int n1 = n;
        n1 = 20;
        System.out.println("n = " + n + "  n1=" + n1);  

上面n和n1的输出结果分别为1,20。这就说明n1值的改变,不影响n的值

基本数据类型之间赋值,属于值传递(值拷贝)

下面从 jvm 层面分析下原理。使用 javap -v xxx.class 命令,获取 字节码 文件的汇编指令

  public static void main(java.lang.String[]) throws java.io.IOException;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=1
         0: iconst_1   //将常量1压入栈中
         1: istore_1  //常量1出栈,保存到局部变量表,槽点为1的位置
         2: iload_1  //常量1入栈
         3: istore_2 // 常量1出栈,保存到局部变量表, 槽点为2的位置
         4: bipush        20  //将常量20压入栈中
         6: istore_2   //常量20出栈,保存到局部变量表,槽点为2的位置
         7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        10: new           #3                  // class java/lang/StringBuilder
        13: dup
        14: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        17: ldc           #5                  // String n =
        19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        22: iload_1
        23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        26: ldc           #8                  // String   n1=
        28: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        31: iload_2
        32: invokevirtual #7                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        35: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        38: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        41: return
      LineNumberTable: //行号表,代码的行号与指令索引的映射关系
        line 58: 0
        line 59: 2
        line 60: 4
        line 61: 7
        line 79: 41
      LocalVariableTable: //局部变量表
        Start  Length  Slot  Name   Signature
            0      42     0  args   [Ljava/lang/String;
            2      40     1     n   I
            4      38     2    n1   I
  

从字节码指令中,不难看出,变量n,n1分别存储在局部变量表的槽点1,2位置上。

  • 执行 int n = 1 ,在LocalVariableTable中的槽点1的位置存放变量n,值为1
  • 执行 int n1 = n ,在LocalVariableTable中的槽点2的位置存放变量n1,值为1
  • 执行 n1 = 20 ,将20赋值给槽点2的变量n1,槽点1中的变量n的值不变。

引用传递

         int[] arr = {1,23,3};
        int[] arr1 = arr;
        arr1[0] = 120;  

问题:

上面代码执行完了,数组arr的第一个元素的值是否也变成了120?


下面咱们从字节码指令进行分析

 public static void main(java.lang.String[]) throws java.io.IOException;
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=3, args_size=1
         0: iconst_3    // 常量3入栈
         1: newarray       int // new一个长度为3的数组
         3: dup // 复制数组对象引用地址入栈
         4: iconst_0 // 数组角标常量0入栈
         5: iconst_1 // 常量1入栈
         6: iastore // 出栈, 将栈顶int型数值1存入数组的索引0的位置  
         7: dup // 复制数组对象引用地址入栈
         8: iconst_1 // 数组角标常量1入栈 
         9: bipush        23 // // 常量23入栈
        11: iastore // 出栈, 将栈顶int型数值23存入数组的索引1的位置  
        12: dup // 复制数组对象引用地址入栈
        13: iconst_2 // 数组角标常量2入栈 
        14: iconst_3 // 常量3入栈 
        15: iastore // 出栈, 将栈顶int型数值3存入数组的索引2的位置  
        16: astore_1 // 数组对象引用地址出栈,保存到局部变量表,槽点1的位置,变量名为arr
        17: aload_1 // 槽点1中的变量arr引用地址入栈
        18: astore_2 // 栈顶变量arr引用地址出栈,保存到局部变量表,槽点2的位置,变量名称为arr1
        19: aload_2 // 槽点2中的变量arr1引用地址入栈
        20: iconst_0· // 角标常量0入栈
        21: bipush        120 //常量120入栈
        23: iastore // 出栈, 将栈顶int型数值120存入数组的索引0的位置
        24: return
      LineNumberTable:
        line 63: 0
        line 64: 17
        line 65: 19
        line 77: 24
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      25     0  args   [Ljava/lang/String;
           17       8     1   arr   [I
           19       6     2  arr1   [I
    Exceptions:
      throws java.io.IOException
    MethodParameters:
      Name                           Flags
      args  

从字节码指令中可以看出,数组arr,arr1都指向了同一个数组对象地址,当对数组某个角标的值进行改变,引用这个数组的所有变量的值都发生了改变。

文章来源:智云一二三科技

文章标题:值传递与引用传递

文章地址:https://www.zhihuclub.com/198403.shtml

关于作者: 智云科技

热门文章

发表回复

您的电子邮箱地址不会被公开。

网站地图