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 Object
array 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 GenSet
as, Anda bisa menetapkan a
ke array tipe itu, dan Anda bisa menetapkan elemen dari a
ke 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.class
bertindak sebagai Class
objek 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
).
Class
itu sendiri generik (dideklarasikan sebagai Class<T>
, di mana T
singkatan dari tipe yang Class
diwakili objek), artinya tipe String.class
is Class<String>
.
Jadi, setiap kali Anda memanggil konstruktor GenSet
, Anda meneruskan literal kelas untuk argumen pertama yang mewakili array dari tipe GenSet
instance yang dinyatakan (misalnya String[].class
untuk GenSet<String>
). Perhatikan bahwa Anda tidak akan bisa mendapatkan array primitif, karena primitif tidak dapat digunakan untuk variabel tipe.
Di dalam konstruktor, memanggil metode cast
mengembalikan Object
argumen yang dilewatkan ke kelas yang diwakili oleh Class
objek tempat metode dipanggil. Memanggil metode statis newInstance
dalam java.lang.reflect.Array
pengembalian sebagai Object
array dari tipe yang diwakili oleh Class
objek yang dilewati sebagai argumen pertama dan panjang yang ditentukan oleh yang int
dilewati sebagai argumen kedua. Memanggil metode getComponentType
mengembalikan Class
objek yang mewakili jenis komponen array yang diwakili oleh Class
objek tempat metode dipanggil (misalnya String.class
untuk String[].class
, null
jika Class
objek tidak mewakili array).
Kalimat terakhir itu tidak sepenuhnya akurat. Memanggil String[].class.getComponentType()
mengembalikan Class
objek 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 Class
yang mengembalikan Class
objek.
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));
}