2009-12-03 45 views
15

我想使用通用列表,但初始化方法只返回List。 下面的代碼工作得很好:泛型和問號

List tmpColumnList = aMethodToInitializeTheColumnList(); 
tmpColumnList.add("ANICELITTLECOLUMN"); 

Java的指責,我使用原始類型,我應該paramerize列表。 所以我添加了問號參數化這個列表。

List<?> tmpColumnList = aMethodToInitializeTheColumnList(); 
tmpColumnList.add("ANICELITTLECOLUMN"); 

問題是:現在add(..)方法行不通了。
我不能保證該列表僅包含String s,因爲aMethodToInitializeTheColumnList()未在我的代碼中實現。

我的錯誤是什麼?

謝謝!

+1

它是如何在第一個片段中工作的?缺少'new' ... – Abel 2009-12-03 13:52:59

+3

Abel:函數調用初始化列表。我會添加它來澄清這件事。 – guerda 2009-12-03 13:54:47

+0

修復初始化方法? – 2009-12-03 13:56:45

回答

26

從泛型教程。感謝Michael's answer

是不安全但是對任意對象 添加到它:

Collection<?> c = new ArrayList<String>(); 
c.add(new Object()); // Compile time error 

因爲我們不知道什麼元素 c型的代表,我們不能 對象添加到它。 add()方法需要 類型爲E的參數,集合的元素類型爲 。當實際的 類型參數是?時,它代表某個未知類型的 。 我們通過 傳遞添加的任何參數必須是此未知類型的子類型 。由於我們不知道 是什麼類型,我們不能通過 任何東西。唯一的例外是 null,它是每種類型的成員。

+4

原諒我的無知(我不是Java人)。如果它不起作用,它的目的是什麼? – jww 2014-03-19 06:52:35

+4

@noloader:目的是這樣的:如果你有一個類型爲'Collection '的方法參數,你可以傳入一個'Collection ',一個'Collection '或一個'Collection ',並且在你可以以'Object'類型獲取這些集合的內容。你不能添加任何東西到集合中很重要,因爲它確保原始類型約束不被違反。 – 2014-03-19 08:09:38

17

您可能想要使用List<String> - 這就是泛型是如何使用的,即添加關於集合中的對象類型的信息。如果你實際上將要有一個包含混合類型的列表(通常表示設計不好),請使用List<Object>

有關使用通配符的更多信息,請參閱Generics Tutorial。但是,在定義自己的泛型類或使用泛型參數的方法時,它們確實非常重要。

+0

感謝您的提示。我不能保證這個列表只包含字符串。 – guerda 2009-12-03 13:54:07

+1

在這種情況下,您可以使用列表或其他可能依賴於您知道列表將包含的內容(例如List ) – Fortega 2009-12-03 13:58:46

+0

在泛型教程中有解決方案,請參閱我自己的答案。我會考慮接受你的答案,因爲你給了我提示。 – guerda 2009-12-03 14:02:11

16

如果您使用<?>,則表示您不打算在任何地方使用參數化類型。要麼去特定類型(在你的情況下,它似乎List<String>)或非常通用List<Object>

+0

我不想指定它,但爲什麼正常的'add'方法失敗呢? – guerda 2009-12-03 13:57:10

+2

好吧,編譯器強制語義一致性。你說你不會使用參數化類型,所以它不會讓你。 'add'方法需要一個參數,該參數的類型是泛型參數,所以如果你沒有指定一個參數,就不允許使用它。 – Romain 2009-12-03 14:12:54

+3

由於類型*未知*。編譯不可能確定一個'String'是否合適,所以你不允許在列表中添加一個'String'。 (實際上,除了'null',你不允許在列表中添加任何東西。) – Bombe 2009-12-03 14:13:22

2

List<?>表示該列表是(或可能)鍵入,但類型未知**。因此,如果您碰巧不屬於該類型,那麼向它添加內容可能是錯誤的**。因爲它是未知的,所以你會被警告。

您可以使用List<Object>,這意味着列表可以包含任何類型

+0

我不僅警告,代碼在編譯時失敗! – guerda 2009-12-03 14:14:10

+0

@furtelwart誠然,我的措辭很差:-)。但是這個編譯時錯誤的地方在於編譯器表示代碼可能是錯誤的。順便說一下,它是泛型子系統的全部實現,在編譯時搜索代碼安全性,並在運行時添加強制轉換... – KLE 2009-12-03 15:49:13

+0

原諒我的無知(我不是Java人)。如果它不起作用,它的目的是什麼? – jww 2014-03-19 06:52:11

8

在這種情況下,另一種選擇是申報清單內容,是

List<? super String> 

,因爲這款車型正是你知道它是什麼。你說你不知道它的類型邊界究竟是什麼,但從第二行開始,假定它必須能夠包含字符串是公平的。

這個編譯和我腦海裏,比List<Object>好一點,因爲它編碼了你對列表中實際可能出現的不確定性。基本上,你只能加入字符串,但是當你調用get()時,返回的元素可能是任何東西(Java將正確地推斷這種類型爲Object)。

實際上,這和List<Object>唯一的區別在於後者會允許tmpColumnList.add(3)tmpColumnList.add(new Thread())等等。我更喜歡它攜帶的語義以及實用性。