java: (String []) List.toArray () ให้ ClassCastException


107

รหัสต่อไปนี้ (ทำงานใน Android) ทำให้ฉันมี ClassCastException ในบรรทัดที่ 3 เสมอ:

final String[] v1 = i18nCategory.translation.get(id);
final ArrayList<String> v2 = new ArrayList<String>(Arrays.asList(v1));
String[] v3 = (String[])v2.toArray();

นอกจากนี้ยังเกิดขึ้นเมื่อ v2 เป็น Object [0] และเมื่อมีสตริงอยู่ด้วย ความคิดใด ๆ ทำไม?


คุณอาจต้องการอ่านเกี่ยวกับ Covariance and Contravariance - en.wikipedia.org/wiki/…
Hut8

แล้วกรณีที่ T เป็นอินเทอร์เฟซที่มีวิธีการโรงงานสำหรับการสร้างอินสแตนซ์
sebaj

2
@LaceCard - นี่เป็นเพียงความสัมพันธ์ทางอ้อมกับความแปรปรวนร่วม / ความแปรปรวนเท่านั้น ปัญหาที่แท้จริงคือนี่เป็นผลโดยตรงจากพฤติกรรมที่ระบุของtoArray()วิธีการ
Stephen C

คำตอบ:


250

เนื่องจากเมื่อคุณใช้

 toArray() 

มันส่งคืน Object [] ซึ่งไม่สามารถส่งไปยัง String [] ได้ (แม้ว่าเนื้อหาจะเป็น Strings ก็ตาม) เนื่องจากเมธอด toArray ได้รับเพียง

List 

และไม่

List<String>

เนื่องจาก generics เป็นซอร์สโค้ดเท่านั้นและไม่สามารถใช้งานได้ที่รันไทม์ดังนั้นจึงไม่สามารถระบุได้ว่าจะสร้างอาร์เรย์ประเภทใด

ใช้

toArray(new String[v2.size()]);

ซึ่งจัดสรรชนิดของอาร์เรย์ที่เหมาะสม (String [] และขนาดที่เหมาะสม)


3
cuz generics นั่นคือเหตุผล
Kaleb Brasee

2
@Kaleb - ไม่จริง หรืออย่างน้อยนั่นก็ไม่ใช่เหตุผลเดิม toArrayวิธีการอยู่ก่อนเรียนคอลเลกชันได้ทั่วไป
Stephen C

10
นี่เป็นวิธีแก้ปัญหาที่ถูกต้อง แต่ไม่ใช่คำอธิบายที่ถูกต้อง คุณไม่สามารถร่าย Object [] เป็น Double [] ได้เนื่องจากเป็นคุณสมบัติของภาษาไม่มีอะไรเพิ่มเติม ไม่จำเป็นต้องเกี่ยวข้องกับ Generics คุณสามารถโยน Object เป็น Double ได้โดยสมมติว่าเป็น Double อย่างแท้จริง ตามเหตุผลแล้วคุณสามารถทำเช่นเดียวกันกับอาร์เรย์ได้ แต่ไม่ใช่ส่วนหนึ่งของภาษา หากคุณร่าย Object เป็น Double จะมีการตรวจสอบรันไทม์เพื่อให้แน่ใจว่า Object เป็น Double จริงๆ หากคุณร่าย Double to Object จะไม่มีการตรวจสอบรันไทม์เนื่องจาก Object อยู่ในลำดับชั้นการสืบทอดของ Double
KyleM

5
เมื่อทำสิ่งนี้ใน IntelliJ ฉันได้รับคำเตือนให้ใช้toArray(new String[0])มากกว่า: "แนะนำให้ใช้ใน Java เวอร์ชันเก่าที่ใช้อาร์เรย์ขนาดล่วงหน้าเนื่องจากการเรียกการสะท้อนกลับซึ่งจำเป็นในการสร้างอาร์เรย์ที่มีขนาดเหมาะสมนั้นค่อนข้างช้าอย่างไรก็ตามตั้งแต่มีการอัปเดต OpenJDK ในช่วงปลาย 6 การเรียกนี้ถูกกำหนดไว้ภายในทำให้ประสิทธิภาพของเวอร์ชันอาร์เรย์ว่างเหมือนเดิมและบางครั้งก็ดีกว่าเดิมนอกจากนี้การส่งอาร์เรย์ขนาดล่วงหน้ายังเป็นอันตรายต่อการรวบรวมพร้อมกันเนื่องจากการแข่งขันระหว่างsizeและการtoArrayโทรเป็นไปได้ "
Mikepote

35

คุณกำลังใช้ผิด toArray()

โปรดจำไว้ว่าชื่อสามัญของ Java ส่วนใหญ่เป็นน้ำตาลที่มีปฏิกิริยา ArrayList ไม่ทราบว่าองค์ประกอบทั้งหมดเป็น Strings

เพื่อแก้ไขปัญหาของคุณโทรtoArray(T[]). ในกรณีของคุณ

String[] v3 = v2.toArray(new String[v2.size()]);

โปรดทราบว่ารูปแบบทั่วไปtoArray(T[])จะส่งกลับT[]ดังนั้นผลลัพธ์จึงไม่จำเป็นต้องถูกโยนอย่างชัดเจน



0
String[] str = new String[list.size()];
str = (String[]) list.toArray(str);

ใช้แบบนี้.


1
กรุณา! จัดรูปแบบรหัสของคุณ! เลือกทั้งหมดที่กด "ctrl + k" หรือเพิ่ม "` "ก่อนอักษรตัวแรกของรหัสและต่อท้ายอีกตัวหนึ่ง คุณยังสามารถเลือก "{}" ในความช่วยเหลือที่ด้านบนเมื่อเขียนคำตอบ!
MK
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.