簡體   English   中英

Java泛型 - ArrayList初始化

[英]Java generics - ArrayList initialization

眾所周知,arraylist init。 應該是這樣的

ArrayList<A> a = new ArrayList<A>();
ArrayList<Integer> a = new ArrayList<Number>(); // compile-time error

所以,為什么java允許這些?

1. ArrayList<? extends Object> a1 = new ArrayList<Object>();
2. ArrayList<?> a2 = new ArrayList<Integer>();

那么,如果他們是正確的,為什么不允許這些呢?

1. a1.add(3);
2. a2.add(3);

編譯器消息是:類型ArrayList中的方法add(int,capture#1-of?extends Object)不適用於參數(int)

更一般

  1. a1.add(null e);
  2. a2.add(? e);

我讀到了這個,但很高興收到你的來信。 謝謝

另一個有趣的觀點是:

 ArrayList<ArrayList<?>> a = new ArrayList<ArrayList<?>>(); // correct
 ArrayList<?> a = new ArrayList<?>(); // wrong. I know it's reason but I have some 
question in my mind that mentioned above 

您不能將List<Number>分配給List<Integer>類型的引用,因為List<Number>允許除Integer之外的數字類型。 如果您被允許這樣做,將允許以下內容:

List<Number> numbers = new ArrayList<Number>();
numbers.add(1.1); // add a double
List<Integer> ints = numbers;
Integer fail = ints.get(0); // ClassCastException!

List<Integer>類型保證它包含的任何內容都是Integer 這就是為什么你可以在沒有強制轉換的情況下從中獲取Integer 如您所見,如果編譯器允許將另一個類型的List (例如Number分配給List<Integer> ,那么保證將被破壞。

List<Integer>分配給類型的引用,例如List<?>List<? extends Number> List<? extends Number>是合法的,因為? 的意思是“給定類型的一些未知子類型”(這里的類型是Object中的正好的情況?Number在的情況下? extends Number )。

既然? 表示您不知道 List將接受哪種特定類型的對象,添加除null任何內容都是不合法的。 但是,您可以從中檢索任何對象,這是使用? extends X的目的? extends X ? extends X有界通配符類型。 請注意,對於一個相反的情況是正確的? super X ? super X有界通配符類型... List<? super Integer> List<? super Integer>是“一個至少是Integer超類型的未知類型的列表”。 雖然您不確切知道它的List類型(可能是List<Integer>List<Number>List<Object> ),但您確實知道無論它是什么,都可以添加一個Integer

最后, new ArrayList<?>()是不合法的,因為當您創建像ArrayList這樣的參數化類的實例時,您必須提供特定的類型參數。 你真的可以使用任何在你的榜樣( ObjectFoo ,沒關系),因為你永遠可以,但添加任何null它,因為你直接分配給它一個ArrayList<?>參考。

關鍵在於引用和實例之間的差異以及引用可以承諾的內容以及實例可以實際執行的操作。

ArrayList<A> a = new ArrayList<A>();

這里a是對特定類型實例的引用 - 恰好是A的數組列表。 更明確地, a是對將接受A s並將產生A s的數組列表的引用。 new ArrayList<A>()A s的數組列表的實例,即一個接受A s並將產生A s的數組列表。

ArrayList<Integer> a = new ArrayList<Number>(); 

這里, a是對Integers數組列表的引用,即完全是一個可以接受Integer並且將產生Integer的數組列表。 它不能指向Number s的數組列表。 Number的數組列表不能滿足ArrayList<Integer> a所有承諾(即Number的數組列表可能產生不是Integer的對象,即使它是空的然后)。

ArrayList<Number> a = new ArrayList<Integer>(); 

在這里,聲明a表示a將完全引用Number s的數組列表,即,恰好是一個接受Number s並將產生Number s的數組列表。 它不能指向數組列表Integer S,因為類型聲明a說, a可以接受任何Number ,但該數組列表Integer s不能接受隨便什么Number ,它只能接受Integer秒。

ArrayList<? extends Object> a= new ArrayList<Object>();

這里a對類型族的 (通用)引用,而不是對特定類型的引用。 它可以指向屬於該系列成員的任何列表。 然而,這個很好的靈活引用的權衡是,如果它是類型特定的引用(例如非泛型),它們不能保證它可以具有的所有功能。 在這種情況下, a是對將生成 Object的數組列表的引用。 但是 ,與特定類型的列表引用,這a參考不能接受任何Object (即,不是家庭的類型的每一個部件,其a可以指向可以接受任何Object ,例如一個數組列表Integer s只能接受Integer秒。)

ArrayList<? super Integer> a = new ArrayList<Number>();

同樣, a是對類型族(而不是單個特定類型)的引用。 由於通配符使用super ,此列表引用可以接受Integer ,但它不能生成Integer 換句話說,我們知道,家里的那類型中的任何一個成員, a可以指向可以接受一個Integer 但是,並非該家族的每個成員都能生成Integer

PECS - 生產者extends ,消費者super - 這個助記符可以幫助您記住使用extends意味着泛型類型可以生成特定類型(但不能接受它)。 使用super意味着泛型類型可以使用 (接受)特定類型(但不能生成它)。

ArrayList<ArrayList<?>> a

一個數組列表,其中包含對作為數組列表類型族成員的任何列表的引用。

= new ArrayList<ArrayList<?>>(); // correct

數組列表的實例,其中包含對作為數組列表類型族成員的任何列表的引用。

ArrayList<?> a

對任何數組列表的引用(數組列表類型系列的成員)。

= new ArrayList<?>()

ArrayList<?>是指一系列數組列表類型中的任何類型,但您只能實例化特定類型。


另請參見如何添加到列表<? 擴展Number>數據結構?

你有奇怪的期望。 如果你給出了引導他們的論據鏈,我們可能會發現它們中的缺陷。 事實上,我只能簡單介紹一下泛型,希望觸及你可能誤解的幾點。

ArrayList<? extends Object> ArrayList<? extends Object>是一個ArrayList,其類型參數已知為Object或其子類型。 (是的,類型邊界中的擴展具有除直接子類之外的含義)。 由於只有引用類型可以是類型參數,因此這實際上等同於ArrayList<?>

也就是說,您可以將ArrayList<String>放入使用ArrayList<?>聲明的變量中。 這就是a1.add(3)是編譯時錯誤的原因。 a1的聲明類型允許a1ArrayList<String> ,不能添加任何Integer

顯然, ArrayList<?>不是很有用,因為你只能在其中插入null。 這可能就是Java Spec 禁止它的原因:

如果類實例創建表達式中使用的任何類型參數是通配符類型參數,那么這是編譯時錯誤

相反, ArrayList<ArrayList<?>>是功能數據類型。 您可以將各種ArrayLists添加到其中,並檢索它們。 由於ArrayList<?>包含不是通配符類型,因此上述規則不適用。

很多這與多態性有關。 當你分配

X = new Y();

X可以比Y更“特異”,但不是相反。 X只是你正在訪問Y的句柄,Y是真正實例化的東西,

這里出現錯誤,因為Integer是一個Number,但Number不是Integer。

ArrayList<Integer> a = new ArrayList<Number>(); // compile-time error

因此,您調用的任何X方法必須對Y有效。由於X更一般地它可能共享一些但不是所有Y的方法。 但是,任何給出的論點必須對Y有效。

在使用add的示例中,int(小i)不是有效的Object或Integer。

ArrayList<?> a = new ArrayList<?>();

這不好,因為你實際上無法實例化包含?的數組列表。 你可以聲明一個,然后在new ArrayList<Whatever>();

想想? 至於意思是"unknown" 因此, "ArrayList<? extends Object>"是指“一個未知類型(或只要它)擴展Object”。 因此,需要說的是, arrayList.add(3)會把你知道的東西放到一個未知的地方。 即'遺忘'。

ArrayList<Integer> a = new ArrayList<Number>(); 

因為Number是Integer的超類這一事實不起作用並不意味着List<Number>List<Integer>的超類。 泛型在編譯期間被刪除,並且在運行時不存在,因此無法實現集合的父子關系:僅刪除有關元素類型的信息。

ArrayList<? extends Object> a1 = new ArrayList<Object>();
a1.add(3);

我無法解釋為什么它不起作用。 這真的很奇怪,但這是事實。 真的語法<? extends Object> <? extends Object>主要用於方法的返回值。 即使在此示例中, Object o = a1.get(0)也是有效的。

ArrayList<?> a = new ArrayList<?>()

這不起作用,因為您無法實例化未知類型的列表...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM