JVM中的直接引用和符號引用
JVM在裝載class檔案的時候,會有一步是將符號引用解析為直接引用的過程。
那麼這裡的直接引用到底是什麼呢?
對於指向“型別”【Class物件】、類變數、類方法的直接引用可能是指向方法區的本地指標。
指向例項變數、例項方法的直接引用都是偏移量。例項變數的直接引用可能是從物件的映像開始算起到這個例項變數位置的偏移量。例項方法的直接引用可能是方法表的偏移量。
在《深入java虛擬機器》書的第197頁我們可以看到,子類中方法表的偏移量和父類中的方法表的偏移量是一致的。比如說父類中有一個say()方法的偏移量是7,那麼子類中say方法的偏移量也是7。
書中第199頁說,通過“介面引用”來呼叫一個方法,jvm必須搜尋物件的類的方法表才能找到一個合適的方法。這是因為實現同一個介面的這些類中,不一定所有的介面中的方法在類方法區中的偏移量都是一樣的。他們有可能會不一樣。這樣的話可能就要搜尋方法表才能確認要呼叫的方法在哪裡。
而通過“類引用”來呼叫一個方法的時候,直接通過偏移量就可以找到要呼叫的方法的位置了。【因為子類中的方法的偏移量跟父類中的偏移量是一致的】
所以,通過介面引用呼叫方法會比類引用慢一些。
下面介紹下什麼是介面引用。
interface A{void say();}
class B implements A{}
class C{public static void main(String []s){A a=new B();a.say()}}
在上面的第三行程式碼中,就是用“介面引用”來呼叫方法。
--------------------------------------------------------------------
符號引用:
符號引用是一個字串,它給出了被引用的內容的名字並且可能會包含一些其他關於這個被引用項的資訊——這些資訊必須足以唯一的識別一個類、欄位、方法。這樣,對於其他類的符號引用必須給出類的全名。對於其他類的欄位,必須給出類名、欄位名以及欄位描述符。對於其他類的方法的引用必須給出類名、方法名以及方法的描述符。
總結:JVM對於直接引用和符號引用的處理是有區別的,可以看到符號引用時,JVM將使用StringBuilder來完成字串的 新增,而直接引用時則直接使用String來完成;直接引用永遠比符號引用效率更快,但實際應用開發中不可能全用直接引用,要提高效能可以考慮按虛擬機器的思維來編寫你的程式。
1.0 直接引用:
public class StringAndStringBuilder{ public static void main(String[] args){ System.out.println ("s=" + "asdfa"); } }
反編譯後的:
F:\java\res\位元組碼>javap -c StringAndStringBuilder Compiled from "StringAndStringBuilder.java" public class StringAndStringBuilder extends java.lang.Object{ public StringAndStringBuilder(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return
public static void main(java.lang.String[]); Code: 0: ldc #2; //String asdfa 2: astore_1 3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 6: ldc #4; //String s=asdfa 8: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/Str ing;)V 11: return
}
2.0 符號引用:
public class StringAndStringBuilder{ public static void main(String[] args){ String s="asdfa"; System.out.println ("s=" + s); } }
反編譯後的:
F:\java\res\位元組碼>javap -c StringAndStringBuilder Compiled from "StringAndStringBuilder.java" public class StringAndStringBuilder extends java.lang.Object{ public StringAndStringBuilder(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return
public static void main(java.lang.String[]); Code: 0: ldc #2; //String asdfa 2: astore_1 3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 6: new #4; //class java/lang/StringBuilder 9: dup 10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V 13: ldc #6; //String s= 15: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/ String;)Ljava/lang/StringBuilder; 18: aload_1 19: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/ String;)Ljava/lang/StringBuilder; 22: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/la ng/String; 25: invokevirtual #9; //Method java/io/PrintStream.println:(Ljava/lang/Str ing;)V 28: return
}