1. 程式人生 > >Java符號引用與直接引用

Java符號引用與直接引用

Java 符號引用與直接引用

1. 定義(深入理解JVM第182頁)

  • 符號引用

       符號引用以一組符號來描述所引用的目標,符號可以是任意形式的字面量,只要使用時能無歧義的定位到目標即可。符號與虛擬機器實現的記憶體佈局無關,引用目標並不一定載入到記憶體中(方法區)。

  • 直接引用

       直接引用可以指向目標的指標相對偏移量或者是一個能夠直接定位到目標的控制代碼。直接引用於虛擬機器的記憶體佈局相關,同一個符號引用在不同的虛擬機器例項上翻譯出來的直接引用一般不同。如果有了直接引用,那麼,所引用的目標一定已經在記憶體中存在。

2. 理解

***符號引用:***        一個類可能使用另外類或者介面的欄位或者呼叫另外一個類的方法。在java檔案編譯為class檔案時,java類並不知道其所引用類的記憶體地址(也可能未載入到記憶體中),因此只能用符號引用來表示。        虛擬機器根據需要來判斷,到底是類載入器載入時就對常量池中的符號引用進行解析,還是等到一個符號引用將要被使用前才去解析它。        例如:下面程式碼。

3. 程式碼

  • 直接引用

        定義一個常量類RefCons:

public class RefCons {

    public static final String TEST_STR = "test";

}

        定義一個類SymbolRef引用RefCons中的欄位:

public class SymbolRef {

    private static String str = RefCons.TEST_STR;

    public static void main(String[] args) {
        System.out.println("str = " + str);
    }
}

       利用javap -verbose 分析:

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: ldc           #11                 // String test
         2: putstatic     #7                  // Field str:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 12: 0
}

       由於編譯時已經可以確定RefCons.TEST_STR的值,在此處為直接引用

  • 符號引用
public class DirectRef {

    public static int iVal = new Random().nextInt();

    public static void main(String[] args) {
        System.out.println(iVal);
    }
    
}

       利用javap -verbose 分析:

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #5                  // class java/util/Random
         3: dup
         4: invokespecial #6                  // Method java/util/Random."<init>":()V
         7: invokevirtual #7                  // Method java/util/Random.nextInt:()I
        10: putstatic     #3                  // Field iVal:I
        13: return
      LineNumberTable:
        line 14: 0
}

       第十行中 putstatic #10// Field iVal:I對應變數為常量池中第10項的符號引用,只有在執行後可以知到其值:

#10 = Fieldref           #39.#40        // reference/RefCons.TEST_STR:Ljava/lang/String;
#39 = Class              #53            // reference/RefCons
#40 = NameAndType        #54:#14        // TEST_STR:Ljava/lang/String;

參考

1.https://blog.csdn.net/kkdelta/article/details/17752097 2.https://blog.csdn.net/maerdym/article/details/8087620