2011-09-02 40 views
5

我有一個使用方法的可變參數功能:如何將列表的內容傳遞給可變參數方法?

void add(Animal ...); 

現在,而不是做.add(dog, cat),我有數目不詳的元素的動物名單,

List<Animal> i = new ArrayList<Animal>(); 
i.add(dog); 
i.add(cat); 

,並要撥打添加具有這個列表的元素。

我想我可以使用一個數組,但是當我做.add(i.toArray())時,它給出了一個編譯器錯誤。

什麼是正確的方法來做到這一點?

+0

我不明白這個問題。你創建了自己的方法'add(Animal ...)',但是你調用ArrayList.add(Object)而不是你自己的方法。這是爲什麼?請使用代碼的上下文編輯問題。你的'add'方法中的代碼塊是什麼?如果你唯一的問題是你不能將Object []轉換爲Animal [],那麼按照@Tom的回答。 – aalku

+0

只是對將來的說明:如果您有編譯器錯誤,請複製完整的錯誤消息以及與此消息相關的源代碼行。 –

回答

10

它是:

add(i.toArray(new Animal[i.size()])) 

List.toArray返回Object[],無論在列表中的參數的類型:即使你可能寫new List<String>().toArray(),你會得到一個Object[]。但是,version of toArray that takes an array to fill會返回一個正確類型的數組:如果您編寫了new List<String>().toArray(new String[0]),您將得到一個String[]。請注意,您傳入的數組的大小甚至不必與列表的大小相匹配,儘管確保它的確很好。

這最終是由於泛型的一個輕度棘手的功能。乍一看,你可能會認爲String[]List<String>對於它們的基本類型意味着類似的東西 - 一個是字符串數組,另一個是字符串列表。

然而,他們其實是非常不同的。

數組是一種語言原語,並且它的類型已經烘焙到其中。如果您使用了十六進制編輯器並在JVM的內存中查看了一個數組實例,那麼您將能夠找到(位於附近的某個地方)所保存對象類型的記錄。這意味着如果你拿一個未知組件類型的數組的實例,你可以使用find out what that type is。相反,這意味着如果你打算去create an instance of an array,你需要知道你想要什麼組件類型。

List,在另一方面,使用泛型,這在Java中與type erasure實施,這意味着,粗略地講,它是什麼,存在於編譯器,而不是在運行時(編譯器可以檢查你做對了,但JVM不能)。這導致了一個簡單而有效的實現(一個足夠簡單的已經被添加到pre-generics Java而無需更改JVM),但它有一些缺點 - 特別是在運行時,無法告訴類型參數在泛型類的任何特定實例上,因爲類型參數只存在於編譯器中。由於List實例需要處理toArray(),因此它唯一能做的就是創建一個Object[]。它只是不知道使用更具體的類型。看這個

的一種方法是,數組有一個類型參數作爲自己類的一部分,而List■找一個類型參數作爲自己類型的一部分,因爲對象有類,但變量具有類型,您不能從一個對象中獲取List的類型實參,只能從保存對象的變量中獲得(另外,您也不能從包含數組的變量中獲取數組的類型實參(考慮Object[] array = new String[0];),但這並不重要,因爲變量可以讓你獲得一個對象 - 除非它爲空)。

熬下來代碼,問題是:

public <E> E[] createSimilarlyTypedArray(List<E> list) { 
    Class<E> componentType = list.???; // there is no way to do this 
    return Arrays.newInstance(componentType, list.size()); 
} 
+0

它將使用你的數組,如果它足夠大或分配一個新的,如果它不是。 – aalku

+0

當你在沒有泛型類型的List上調用i.toArray(new Animal [])時,你會得到一個類型轉換異常嗎? –

+1

@Benjamin:不,你不會的。嘗試運行'陣列。 (「hello」)。toArray(new String [1]);' - 它完美的工作。靜態的,這很好,因爲'toArray'版本從它的參數中選擇了它的類型參數,而不是擁有'List'(奇怪但是正確!),並且動態地,因爲在運行時List類型已被刪除。 –

0

當我這樣做。新增(i.toArray()),它提供了一個錯誤,是什麼做的正確方法 ?

使用foo.addAll(i)然後如果需要將foo轉換爲數組。

0

您的方法void add(Animal...)需要Animal類的對象或其中包含Animal對象的數組。你給它一個Object類的對象。給列表一個泛型類型,像這樣:

List<Animal> animals = new ArrayList<Animal>(); 
animals.add(dog); 
animals.add(cat) 

然後解析列表作爲參數,同時將其轉換爲一個數組,你的方法,像這樣:

add(animals.toArray(new Animal[animals.size()]); 

更多的仿製藥可以發現Java API

http://download.oracle.com/javase/1,5.0/docs/guide/language/generics.html

+1

不止期待「一個包含Animal對象的數組」,它需要一個自己的類型爲Animal []的數組。 'toArray'的零參數形式創建一個包含'Animal'對象的數組 - 一個基本上是'new Object [] {new Animal()}'的數組。然而,所需要的是'new Animal [] {new Animal()}'。陣列和泛型之間的交匯是一個非常危險的水域! –

相關問題