1) Ada banyak contoh di Internet dan StackOverflow tentang masalah khusus dengan obat generik dan vararg. Pada dasarnya, ini terjadi ketika Anda memiliki jumlah variabel argumen tipe-parameter:
<T> void foo(T... args);
Di Jawa, vararg adalah gula sintaksis yang mengalami "penulisan ulang" sederhana pada waktu kompilasi: parameter tipe vararg X...
diubah menjadi parameter tipe X[]
; dan setiap kali panggilan dilakukan ke metode varargs ini, kompiler mengumpulkan semua "argumen variabel" yang masuk dalam parameter varargs, dan membuat array seperti new X[] { ...(arguments go here)... }
.
Ini bekerja dengan baik ketika jenis varargs seperti beton String...
. Ketika itu adalah variabel tipe seperti T...
, itu juga berfungsi ketika T
dikenal sebagai tipe konkret untuk panggilan itu. misalnya jika metode di atas adalah bagian dari sebuah kelas Foo<T>
, dan Anda memiliki Foo<String>
referensi, kemudian memanggil foo
di atasnya akan baik-baik saja karena kita tahu T
adalah String
pada saat itu dalam kode.
Namun, itu tidak berfungsi ketika "nilai" dari T
parameter tipe lain. Di Jawa, tidak mungkin untuk membuat larik tipe komponen-tipe ( new T[] { ... }
). Jadi Java malah menggunakan new Object[] { ... }
(di sini Object
adalah batas atas T
; jika ada batas atas adalah sesuatu yang berbeda, itu akan menjadi bukan Object
), dan kemudian memberi Anda peringatan kompiler.
Jadi apa yang salah dengan menciptakan new Object[]
bukan new T[]
atau apa pun? Nah, array di Java tahu tipe komponen mereka saat runtime. Dengan demikian, objek array yang dikirimkan akan memiliki tipe komponen yang salah saat runtime.
Untuk kemungkinan penggunaan paling umum dari varargs, cukup untuk beralih ke elemen-elemen, ini bukan masalah (Anda tidak peduli dengan tipe runtime dari array), jadi ini aman:
@SafeVarargs
final <T> void foo(T... args) {
for (T x : args) {
// do stuff with x
}
}
Namun, untuk apa pun yang bergantung pada tipe komponen runtime dari array yang diteruskan, itu tidak akan aman. Berikut adalah contoh sederhana dari sesuatu yang tidak aman dan macet:
class UnSafeVarargs
{
static <T> T[] asArray(T... args) {
return args;
}
static <T> T[] arrayOfTwo(T a, T b) {
return asArray(a, b);
}
public static void main(String[] args) {
String[] bar = arrayOfTwo("hi", "mom");
}
}
Masalahnya di sini adalah bahwa kita bergantung pada jenis yang args
akan digunakan T[]
untuk mengembalikannya T[]
. Tetapi sebenarnya jenis argumen saat runtime bukan turunan dari T[]
.
3) Jika metode Anda memiliki argumen tipe T...
(di mana T adalah parameter tipe apa pun), maka:
- Aman: Jika metode Anda hanya bergantung pada fakta bahwa elemen array adalah instance dari
T
- Tidak Aman: Jika itu tergantung pada fakta bahwa array adalah turunan dari
T[]
Hal-hal yang bergantung pada tipe runtime dari array meliputi: mengembalikannya sebagai tipe T[]
, meneruskannya sebagai argumen ke parameter tipe T[]
, mendapatkan tipe array menggunakan .getClass()
, meneruskannya ke metode yang bergantung pada tipe runtime dari array, seperti List.toArray()
dan Arrays.copyOf()
, dll.
2) Perbedaan yang saya sebutkan di atas terlalu rumit untuk dibedakan secara otomatis.