ต่อไปนี้เป็นวิธีใช้ generics เพื่อให้ได้อาร์เรย์ของประเภทที่คุณกำลังมองหาอย่างแม่นยำในขณะที่รักษาความปลอดภัยของประเภท (ตรงข้ามกับคำตอบอื่น ๆ ซึ่งจะทำให้คุณกลับObjectอาร์เรย์หรือส่งผลให้คำเตือนในเวลารวบรวม):
import java.lang.reflect.Array;
public class GenSet<E> {
private E[] a;
public GenSet(Class<E[]> clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet<String> foo = new GenSet<String>(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
}
}
คอมไพล์ดังกล่าวโดยไม่มีการเตือนและอย่างที่คุณเห็นในmainทุกประเภทที่คุณประกาศอินสแตนซ์GenSetคุณสามารถกำหนดให้aกับอาเรย์นั้นและคุณสามารถกำหนดอิลิเมนต์จากaตัวแปรประเภทนั้นซึ่งหมายความว่าอาเรย์ และค่าในอาร์เรย์เป็นประเภทที่ถูกต้อง
มันทำงานโดยการใช้ตัวอักษรระดับเป็นชนิดรันไทม์ราชสกุลตามที่กล่าวไว้ในJava สอน java.lang.Classตัวอักษรระดับได้รับการรักษาโดยรวบรวมเป็นกรณีของ .classเพื่อการใช้งานอย่างใดอย่างหนึ่งเพียงทำตามชื่อของชั้นเรียนกับที่ ดังนั้นString.classทำหน้าที่เป็นวัตถุที่เป็นตัวแทนของชั้นเรียนClass Stringนอกจากนี้ยังใช้งานได้สำหรับอินเทอร์เฟซ enums อาร์เรย์ใด ๆ ในมิติ (เช่นString[].class) ดั้งเดิม (เช่นint.class) และคำหลักvoid(เช่นvoid.class)
Classตัวเองเป็นทั่วไป (ประกาศเป็นClass<T>ที่Tยืนสำหรับประเภทที่ว่าClassวัตถุที่เป็นตัวแทน) ซึ่งหมายความว่าประเภทของการมีString.classClass<String>
ดังนั้นเมื่อใดก็ตามที่คุณเรียกใช้นวกรรมิกGenSetคุณจะส่งผ่านตัวอักษรคลาสสำหรับอาร์กิวเมนต์แรกที่แทนอาร์เรย์ของGenSetชนิดที่ประกาศของอินสแตนซ์ (เช่นString[].classสำหรับGenSet<String>) โปรดทราบว่าคุณจะไม่สามารถรับชุดข้อมูลพื้นฐานได้เนื่องจากไม่สามารถใช้ชุดดั้งเดิมสำหรับตัวแปรประเภทได้
ภายใน Constructor การเรียกเมธอดcastส่งคืนObjectอาร์กิวเมนต์ที่ส่งผ่านไปยังคลาสที่แสดงโดยClassวัตถุที่เมธอดถูกเรียก เรียกวิธีการคงnewInstanceอยู่ในjava.lang.reflect.Arrayผลตอบแทนที่เป็นObjectอาร์เรย์ของประเภทที่แสดงโดยที่Classวัตถุผ่านเป็นอาร์กิวเมนต์แรกและระยะเวลาที่ระบุโดยintผ่านเป็นอาร์กิวเมนต์ที่สอง โทรวิธีการที่getComponentTypeผลตอบแทนClassวัตถุที่เป็นตัวแทนของประเภทองค์ประกอบของอาร์เรย์ตัวแทนจากClassวัตถุที่วิธีการที่เรียกว่า (เช่นString.classสำหรับString[].class, nullถ้าClassวัตถุไม่ได้เป็นตัวแทนอาร์เรย์)
ประโยคสุดท้ายนั้นไม่ถูกต้องทั้งหมด การโทรString[].class.getComponentType()ส่งคืนClassวัตถุที่เป็นตัวแทนของคลาสStringแต่ชนิดของมันคือClass<?>ไม่ใช่Class<String>ซึ่งเป็นสาเหตุที่คุณไม่สามารถทำสิ่งต่อไปนี้
String foo = String[].class.getComponentType().cast("bar"); // won't compile
กันไปสำหรับทุกวิธีในการClassที่ส่งกลับClassวัตถุ
เกี่ยวกับความคิดเห็นของโจอาคิมซาวเออร์เกี่ยวกับคำตอบนี้ (ฉันไม่มีชื่อเสียงพอที่จะให้ความเห็นด้วยตนเอง) ตัวอย่างที่ใช้การส่งT[]จะส่งผลให้เกิดการเตือนเนื่องจากคอมไพเลอร์ไม่สามารถรับประกันความปลอดภัยประเภทในกรณีนั้น
แก้ไขเกี่ยวกับความคิดเห็นของ Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}