2011-08-05 135 views
12

在一塊我寫的代碼,我有這樣一行:無法從ArrayList中<Parcelable>轉換爲ArrayList的<ClSprite>

  AllSprites = (ArrayList<ClSprite>) savedInstanceState.getParcelableArrayList("AllSprites"); 

我得到一個錯誤有關從ArrayList<Parcelable>的無效轉換到ArrayList<ClSprite>。爲什麼這不合法?

+0

返回元素類型......好了,什麼是你的** **的問題? –

+0

[Java中的泛型]的可能重複(http://stackoverflow.com/questions/1794842/generics-in-java) – Thilo

+2

看看標題,無法從ArrayList 投射到ArrayList

回答

7

ArrayList<Derived>投射到ArrayList<Base>或反之亦然是基本不安全的。這樣做會在類型系統中出現漏洞,如果您嘗試這樣做,Java將在運行時拋出ClassCastException

的原因是,我可以做這樣的事情:

ArrayList<Derived> derived = new ArrayList<Derived>(); 
ArrayList<Base> base = (ArrayList<Derived>) derived; // Not legal! 
base.add(new Base()); // Just put a Base into the list, but it only holds Derived! 
derived.get(0).doSomethingOnlyInDerived(); // Error! It's not really a Derived! 

這是什麼原因,順便說一下,那陣列之間Java的隱式轉換斷了,爲什麼有ArrayStoreException。這種情況在所有情況下都不安全。

5

這種轉換在Java中是非法的;不能將父列表轉換爲子列表。此外,投到ArrayList<X>是危險和過度限制。您可以通過使AllSprites的類型爲List<Parcelable>來解決這兩個問題。

+0

我該如何做到這一點,因爲我需要我的自定義類ClSprites中的函數。 –

+0

您可以在使用它時在'List'中投射每個對象,或者您可以創建一個新的'List ',並將對象從另一個列表中移動到'for'循環中。這兩種解決方案都不是很理想,但我恐怕沒有更清晰的方法。 –

17

其他人已經解釋了這個問題,但在這種情況下,它有一個非常簡單的解決方案。 只需離開演員陣容,您的代碼即可編譯。 :):

ArrayList<ClSprite> AllSprites = savedInstanceState.getParcelableArrayList("AllSprites"); 

爲什麼?

看看在getParcelableArrayList方法的簽名:

public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key) 

這是一個通用的方法,它的類型參數必須是Parcelable一個孩子。如果你直接給它這樣一個變量:

ArrayList<ClSprite> AllSprites; // declaration somewhere 
           // ClSprite implements Parcelable 
... 

AllSprites = savedInstanceState.getParcelableArrayList("AllSprites"); 

編譯器可以推斷類型參數,所以沒有必要投了!推導後,簽名是這樣的:

public ArrayList<ClSprite> getParcelableArrayList(String key) 

很顯然,我們沒有投從ArrayList<ClSprite>ArrayList<ClSprite>。 :)

但是,爲什麼你有這個錯誤?如果您執行強制轉換並且不將該變量直接分配給此方法的返回值,那麼編譯器無法推導出類型參數,它只知道返回的類型爲ArrayList<Parcelable>。在這種情況下,錯誤發生在別人已經解釋的地方。

此外,如果該方法不會是通用的,但這樣的:

public ArrayList<Parcelable> getParcelableArrayList(String key) 

你不能返回值分配給AllSprites,因爲沒有類型推演可言,而且不能從ArrayList<Parcelable>轉換爲ArrayList<ClSprite>。 儘管這很有意義,但Java對泛型使用type erasure,並且在運行時使這些事情變得不安全。

+0

感謝您的好解釋,我試圖使用三元運算符設置ArrayList 的值,該運算符不起作用。這個答案完美地解釋了它。 –

+0

感謝這個bug我永遠,我愛你 –

25

一個簡單的辦法是設置像這樣

ArrayList<ClSprite> AllSprites = savedInstanceState.<ClSprite>getParcelableArrayList("AllSprites")

+5

這是對這個問題最簡單明智的答案。這應該是我所接受的答案。 – tasomaniac

+0

非常好的答案! – Pauland

+0

它與javac編譯器兼容(由AndroidStudio使用)。我在eclipse中使用的泛型轉換工作,但不適用於Android Studio。應該接受答案。 – bajicdusko

-1
ArrayList<NewPost> news = new ArrayList<>(); 
news.addAll(List); 
+2

請爲您的代碼添加說明,以便海報可以更好地瞭解您的解決方案。 –

+0

可以通過一種簡單的方式來理解: 較大的那些不能包含在較小的內容中 列表較大 ArrayList較小 您只能列出list.add(ArrayList); 希望能幫助你! –

相關問題