2013-02-02 44 views
3

我不記得在Java字節碼中看到任何參考變量類型的概念。我知道關於刪除類型的一些信息,但這個術語似乎與泛型緊密相關,而我的問題一般是關於對象引用變量。 Java對象引用變量類型是否可以繼續編譯?或者變量類型只是幫助編譯器幫助開發人員檢查代碼是否合理? 如果引用變量類型能夠在編譯之後生效,它們在哪裏出現在字節碼中?編譯後Java對象引用變量類型會發生什麼?

編輯: 請允許我在此感謝您的寶貴貢獻。爲了縮小多一點什麼我腦子裏想的,我想補充一個例子:

Object o = "foo"; 

在字節碼,將變量o和它的類型(對象)在任何地方代表及在讀運行 ?

+1

編譯後不存在泛型。 – Mob

回答

6

是的,字節碼也是類型安全的。首先,有是垂頭喪氣使用每次一個字節代碼instruction called checkcast

Object obj = "abc"; 
String s = (String)obj; 

被翻譯成:

aload_1  
checkcast  #3     // class java/lang/String 
astore_2 

其次invokevirtual和別人期望給定類型的對象。如果你傳遞了錯誤的類型,JVM將拒絕加載這樣的類。我不認爲它是用Java語言實現的,所以我做了一些黑客攻擊。下面的代碼:

Integer x = 1; 
String s = "abc"; 
int len = s.length(); 

被翻譯成:

0: iconst_1  
    1: invokestatic #2     // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
    4: astore_1  
    5: ldc   #3     // String abc 
    7: astore_2  
    8: aload_2  
    9: invokevirtual #4     // Method java/lang/String.length:()I 
    12: istore_3  

加載s局部變量通知指令8。使用十六進制編輯器我換成aload_2aload_1,從而試圖調用String.length()一個Integer對象(x局部變量)上:

$ java Test 

Exception in thread "main" java.lang.VerifyError: 
    Bad type on operand stack in method Test.main([Ljava/lang/String;)V at offset 9 

只是如果你很好奇,如果禁用類驗證,地獄破散:

$ java -Xverify:none Test 
Exception in thread "main" java.lang.NullPointerException 
    at java.lang.String.length(String.java:623) 
    at Test.main(Test.java:6) 

可能會變得更糟。


最後但並非最不重要的,有大量的專用於特定的基元的操作碼(浮點,雙精度數整數等)

1

的類型的字段在field descriptor進行編碼。

局部變量的類型可以編碼爲LocalVariableTable attribute(或泛型類型的LocalVariableFieldTypeTable attribute),並且在以Java 6爲目標的類文件中,必須編碼爲StackMapTable attribute。對於較舊的類文件,JVM將使用type inference驗證字節碼的類型正確性。

所以,雖然你是正確的字段和變量的類型不是以字節碼錶示,它們是在類文件(至少對於目標Java 6或更高版本的類文件)。

+1

LocalVariable表格純粹用於顯示調試信息,並且不影響代碼的實際執行。你甚至不需要包含它們。 – Antimony

+0

我既不聲稱他們是強制性的,也不用於執行代碼。 – meriton

2

JVM加載的所有字節碼都是靜態類型檢查,以確保它是安全的。如果不進行類型檢查,惡意字節碼可能會將int視爲指針並破壞虛擬機。

但是,僅僅因爲字節碼是類型安全的並不意味着它有明確的鍵入。相反,每個值都有一個由類型推斷確定的隱式類型。 (從Java 7開始,還必須在每個基本塊的開始處包含指定所有內容的元數據,這使得類型推斷任務變得更加簡單)。

請注意,儘管所有內容都經過了類型檢查,但規則比Java更爲鬆散。例如,在字節碼中,不存在布爾,字節,字符或局部短變量等。它們全部被編譯爲整數。所以你可以例如有一個不等於true或false的布爾值。另外,只有在你調用一個方法時纔會檢查接口,所以接口變量實際上可以包含任意的對象。最後,Hotspot VM允許你自由混合byte []和boolean []。

相關問題