2011-08-05 72 views
12

Trong một đoạn mã tôi đã viết, tôi có dòng này:Không thể đúc từ ArrayList <Parcelable> để ArrayList <ClSprite>

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

Tôi nhận được một lỗi về một diễn viên không hợp lệ từ một ArrayList<Parcelable> để ArrayList<ClSprite>. Tại sao điều này không hợp pháp?

+0

... Được rồi, vì vậy ** câu hỏi của bạn là gì **? –

+0

có thể trùng lặp của [Generics in Java] (http://stackoverflow.com/questions/1794842/generics-in-java) – Thilo

+2

Nhìn vào tiêu đề, Không thể truyền từ ArrayList sang ArrayList

Trả lời

7

Về cơ bản không an toàn để đúc ArrayList<Derived> đến ArrayList<Base> hoặc ngược lại. Làm như vậy sẽ mở ra một lỗ hổng trong hệ thống kiểu, và Java sẽ ném một ClassCastException vào thời gian chạy nếu bạn thử điều này.

Lý do là tôi có thể làm một cái gì đó như thế này:

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! 

Đây là lý do, bằng cách này, mà chuyển đổi tiềm ẩn của Java giữa mảng bị phá vỡ và tại sao có ArrayStoreException. Dàn diễn viên này không an toàn trong mọi trường hợp.

5

Dàn diễn viên đó chỉ đơn giản là bất hợp pháp trong Java; một danh sách-của-cha mẹ không thể được đúc vào một danh sách-của-con. Hơn nữa, dàn diễn viên vào ArrayList<X> là nguy hiểm và quá hạn chế. Bạn có thể khắc phục cả hai vấn đề bằng cách tạo loại AllSpritesList<Parcelable>.

+0

Làm cách nào để thực hiện điều này khi tôi cần các hàm trong lớp tùy chỉnh của tôi, ClSprites. –

+0

Bạn chỉ có thể bỏ từng đối tượng trong 'Danh sách' khi bạn sử dụng nó, hoặc bạn có thể tạo một' Danh sách 'mới và di chuyển các đối tượng từ danh sách khác trong vòng lặp' for'. Không có giải pháp nào có vẻ lý tưởng nhưng tôi sợ không có cách nào sạch hơn. –

17

Những người khác đã giải thích vấn đề, nhưng trong trường hợp này, có một giải pháp rất đơn giản cho nó. Chỉ cần rời khỏi dàn diễn viên và mã của bạn sẽ biên dịch. :):

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

Tại sao?

Hãy nhìn vào chữ ký của phương pháp getParcelableArrayList:

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

Đó là một phương pháp chung chung mà tham số kiểu phải là một đứa trẻ của Parcelable. Nếu bạn gán trực tiếp cho một biến như sau:

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

AllSprites = savedInstanceState.getParcelableArrayList("AllSprites"); 

trình biên dịch có thể suy ra thông số loại, vì vậy không cần đúc gì cả! Sau khi suy luận, chữ ký sẽ trông như thế này:

public ArrayList<ClSprite> getParcelableArrayList(String key) 

Rõ ràng, chúng ta không cần phải đúc từ ArrayList<ClSprite> để ArrayList<ClSprite>. :)

Nhưng tại sao bạn gặp lỗi này? Nếu bạn thực hiện một diễn viên và không gán biến trực tiếp cho giá trị trả về của phương thức này, trình biên dịch không thể suy ra tham số kiểu, nó chỉ biết rằng kiểu trả về là ArrayList<Parcelable>. Và trong trường hợp này, lỗi xảy ra ở những nơi mà những người khác đã giải thích.

Ngoài ra nếu phương pháp này sẽ không được chung chung, nhưng như thế này:

public ArrayList<Parcelable> getParcelableArrayList(String key) 

bạn không thể gán giá trị trả về để AllSprites, vì không có khấu trừ loại ở tất cả, và bạn không thể chuyển đổi từ ArrayList<Parcelable> để ArrayList<ClSprite>. Mặc dù nó có ý nghĩa, Java sử dụng type erasure cho generics, và làm cho những điều này không an toàn khi chạy.

+0

cảm ơn lời giải thích tuyệt vời, tôi đã cố gắng đặt giá trị cho một ArrayList bằng cách sử dụng toán tử bậc ba, không hoạt động. Và câu trả lời này giải thích nó một cách hoàn hảo. –

+0

Cảm ơn lỗi này mãi mãi, tôi yêu bạn –

25

Một giải pháp đơn giản là để thiết lập các loại nguyên tố trở về như vậy

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

+5

Đây là câu trả lời đơn giản và rực rỡ nhất cho vấn đề này. Đây là câu trả lời được chấp nhận mà tôi đoán. – tasomaniac

+0

Câu trả lời hay nhất! – Pauland

+0

Và nó tương thích với trình biên dịch javac (được sử dụng bởi AndroidStudio). Đúc chung tôi sử dụng các công trình trong nhật thực, nhưng không được sử dụng trong Android Studio. Nên được chấp nhận trả lời. – bajicdusko

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

Vui lòng thêm giải thích cho mã của bạn để người đăng có thể hiểu rõ hơn về giải pháp của bạn. –

+0

Có thể hiểu theo cách đơn giản: Không thể chứa những nội dung lớn hơn trong những cái nhỏ hơn Danh sách lớn hơn ArrayList nhỏ hơn Bạn chỉ có thể list.add (ArrayList); Hy vọng có thể giúp bạn! –

Các vấn đề liên quan