ต่อไปนี้เป็นวิธีใช้ 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.class
Class<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));
}