Berikut ini cara menggunakan obat generik untuk mendapatkan larik tipe tepat yang Anda cari sambil menjaga keamanan tipe (berbeda dengan jawaban lain, yang akan mengembalikan Objectarray atau menghasilkan peringatan pada waktu kompilasi):
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];
}
}
Itu mengkompilasi tanpa peringatan, dan seperti yang Anda lihat main, untuk tipe apa pun yang Anda nyatakan instance GenSetas, Anda bisa menetapkan ake array tipe itu, dan Anda bisa menetapkan elemen dari ake variabel tipe itu, artinya array itu dan nilai-nilai dalam array adalah tipe yang benar.
Ia bekerja dengan menggunakan literal kelas sebagai token jenis runtime, seperti yang dibahas dalam Tutorial Java . Literal kelas diperlakukan oleh kompiler sebagai instance dari java.lang.Class. Untuk menggunakannya, cukup ikuti nama kelas dengan .class. Jadi, String.classbertindak sebagai Classobjek yang mewakili kelas String. Ini juga berfungsi untuk antarmuka, enum, array dimensi apa pun (misalnya String[].class), primitif (mis. int.class), Dan kata kunci void(yaitu void.class).
Classitu sendiri generik (dideklarasikan sebagai Class<T>, di mana Tsingkatan dari tipe yang Classdiwakili objek), artinya tipe String.classis Class<String>.
Jadi, setiap kali Anda memanggil konstruktor GenSet, Anda meneruskan literal kelas untuk argumen pertama yang mewakili array dari tipe GenSetinstance yang dinyatakan (misalnya String[].classuntuk GenSet<String>). Perhatikan bahwa Anda tidak akan bisa mendapatkan array primitif, karena primitif tidak dapat digunakan untuk variabel tipe.
Di dalam konstruktor, memanggil metode castmengembalikan Objectargumen yang dilewatkan ke kelas yang diwakili oleh Classobjek tempat metode dipanggil. Memanggil metode statis newInstancedalam java.lang.reflect.Arraypengembalian sebagai Objectarray dari tipe yang diwakili oleh Classobjek yang dilewati sebagai argumen pertama dan panjang yang ditentukan oleh yang intdilewati sebagai argumen kedua. Memanggil metode getComponentTypemengembalikan Classobjek yang mewakili jenis komponen array yang diwakili oleh Classobjek tempat metode dipanggil (misalnya String.classuntuk String[].class, nulljika Classobjek tidak mewakili array).
Kalimat terakhir itu tidak sepenuhnya akurat. Memanggil String[].class.getComponentType()mengembalikan Classobjek yang mewakili kelas String, tetapi tipenya adalah Class<?>, bukan Class<String>, itulah sebabnya Anda tidak bisa melakukan sesuatu seperti berikut ini.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
Hal yang sama berlaku untuk setiap metode Classyang mengembalikan Classobjek.
Mengenai komentar Joachim Sauer tentang jawaban ini (saya sendiri tidak memiliki cukup reputasi untuk mengomentarinya), contoh menggunakan pemeran T[]akan menghasilkan peringatan karena kompiler tidak dapat menjamin keamanan jenis dalam kasus itu.
Edit tentang komentar Ingo:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}