[英]Why does Java's type erasure not break this?
public class Test {
public static class Nested<T> {
public T val;
Nested(T val) { this.val = val; }
}
public static void main(String[] args) {
Nested<Integer> a = new Nested<Integer>(5);
Nested<Integer> b = new Nested<Integer>(2);
Integer diff = a.val - b.val;
}
}
上面的代碼工作正常。 但是,如果我向嵌套添加一個方法:
T diff(Nested<T> other) { return this.val - other.val; }
我收到編譯錯誤:
operator - cannot be applied to T,T
這對我來說很有意義。 T的類型在運行時被擦除,因此Java不能應用僅為某些類(如Integer)定義的運算符。 但為什么a.val - b.val
有效呢?
編輯:
很多好的答案。 感謝大家。 如果我理解正確的話,它的要點是編譯器可以在a.val - b.val
向Integer添加強制轉換,因為它知道a
和b
被實例化為Nested
。 但是,由於<Integer
>this.val - other.val
發生在泛型函數定義的主體內部(其中T仍然可以是任何東西),編譯器無法添加使“ -
”工作所必需的強制轉換。 這導致了一個更有趣的問題,即,如果Java編譯器能夠內聯,那么像diff這樣的泛型函數是否可以工作?
兩者之間的區別在於您是在通用方法中還是在其外部。
你得到的絕對正確的是,在方法T
內部不知道是一個Integer
,所以運算符減去-
不能應用。 但是,當您在main()
,在泛型方法之外時,編譯器知道您已使用Integer
實例化Nested
,因此它非常清楚如何應用運算符。 盡管通用的實施,消除產生的代碼類型Nested<T>
編譯器不會想到a
和b
來講Nested<T>
它有足夠的知識來插入合適的演員,拆箱結果,並申請減號-
運營商。
您將收到編譯時錯誤,而不是運行時錯誤。
public static void main(String[] args) {
Nested<Integer> a = new Nested<Integer>(5);
Nested<Integer> b = new Nested<Integer>(2);
Integer diff = a.val - b.val;
}
在這里,編譯器知道兩個T
都是Integer
。 您剛剛聲明了<Integer>
。
T diff(Nested<T> other) { return this.val - other.val; }
在這里,編譯器不確定T
它可能是任何東西。 並且,僅限數字運算符-
不允許任何內容。
a.val - b.val
工作原理是因為它是由編譯器驗證的,而不是在運行時驗證的。 編譯器“看到”你正在使用<Integer>並且它編譯並運行Ok,在運行時即使擦除也沒有問題,因為編譯器已經驗證了這一點。
因為方法調用是在運行時,並且在編譯時檢查a.val - b.val
。
Integer
並且-
允許整數操作。 T
的類型,因此不確定-
操作是否有效。 因此編譯錯誤。 考慮我們將方法用作diff(Nested<Book> other)
因此無法從其他書中減去書籍。
因為代碼不在嵌套中,所以類型是已知的。 編譯器可以清楚地看到a.val - b.val是一個Integer減去整數,可以自動裝箱。 編譯器基本上將其重寫為
Integer diff = Integer.valueOf(((Integer) a.val).intValue() - ((Integer) b.val).intValue())
.intValue和.valueOf調用來自自動裝箱和自動拆箱。
類型轉換對於編譯器來說是安全的,因為您使用了參數化類型Nested。
確實,從技術上講,a 可能是其他東西,比如Calendar對象,因為類型在運行時是未知的。 但是如果你使用泛型,編譯器會相信你沒有做任何愚蠢的事情來規避它。 因此,如果a.val或b.val不是Integers,則會在運行時拋出ClassCastException。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.