[英]Java generics and the instanceof keyword
所以,我正在查看Oracle Java教程,特別是這段代碼;
List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35)); // compile-time error
可以在這里找到。 這是我的理解(並且請糾正我,如果我錯了)上面的代碼將無法工作,因為編譯器不知道ln
引用了EvenNumbers列表,因此這可以防止您意外添加任何可能是列表的元素的超類型。 如果是這種情況,那么為什么如果你有一個像Number num = new Integer(6);
這樣的語句呢Number num = new Integer(6);
如果編寫if語句,編譯器能夠正確地確定num是一個Integer對象; if (num instanceof Integer) {...}
?
我想我的問題是,編譯器如何能夠確定num
在第二個示例中引用了Integer
對象,但是在第一個示例中無法確定ln
是否引用了List<EvenNumber>
對象?
你的兩個例子是彼此相反的。
Integer
是一個Number
,所以
List<Number> list;
list.add(new Integer(1)); // compiles
但EvenNumber
是一個NaturalNumber
, 而不是相反 ,所以
List<EvenNumber> list;
list.add(new NaturalNumber(1)); // compile error
因為當EvenNumber
是一個NaturalNumber
, NaturalNumber
不是 (一定)的EvenNumber
。
如果在參考案例中交換Integer
和Number
然后重做它,它應該是有意義的,即這將編譯:
List<NaturalNumber> list;
list.add(new EvenNumber(2)); // compiles OK
通常,編譯器能夠確定很多東西,並在優化代碼時使用其觀察結果。
但是,Java是靜態和強類型的語言,編譯器在類型安全方面沒有自由。
1)禁止添加到ln
列表,因為人們不確切地知道它應該包含哪種類型的元素。 在您的示例中,此規則阻止將列表置於無效狀態。
2) “......編譯器能夠正確地確定num是一個整數......”
不是這樣,編譯器不能確定它(盡管如果Java是弱類型語言的話)。
3) num instanceof Integer
這是在運行時評估的,而不是在編譯時評估的。 但是,以下將產生編譯時錯誤:
num instanceof String
因為Number
永遠不能是String
。
這是無法編譯的主要原因是由於這種方式? extends T
? extends T
表現。 一般來說,人們應該熟悉Producer Extends,Consumer Super或PECS。
現在,我還沒有看過這個特殊的代碼示例,但我認為EvenNumber
的層次結構擴展了NaturalNumber
。 這使得賦值語句有效,因為EvenNumber
是一個NaturalNumber
(盡管我打賭數學家們正在NaturalNumber
這個)。
在上面突出顯示的場景中,您無法向集合中添加任何內容的原因是它主要用於讀取。 也就是說,列表是生產者 ,因此它與extends
綁定。
如果您想要讀取和寫入集合,您只需要保留通配符。
你的第二個例子與泛型完全無關 ,而是簡單的繼承。 由於Integer
繼承自Number
,我們可以說Integer
是一個Number
,因此可以被視為一個數字。 任何繼承的類都具有此功能。 檢查Liskov替代原則以獲取更多信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.