Saya mengerti ini terjadi dengan Java 7 saat menggunakan varargs dengan tipe generik;
Tapi pertanyaan saya adalah ..
Apa sebenarnya yang dimaksud Eclipse ketika mengatakan "penggunaannya berpotensi mencemari tumpukan?"
Dan
Bagaimana cara @SafeVarargs
anotasi baru mencegah hal ini?
java
eclipse
generics
variadic-functions
hertzsprung
sumber
sumber
Possible heap pollution from parameterized vararg type
Jawaban:
Polusi tumpukan adalah istilah teknis. Ini merujuk pada referensi yang memiliki tipe yang bukan supertipe dari objek yang mereka tuju.
Ini dapat menyebabkan "tidak dapat dijelaskan"
ClassCastException
.@SafeVarargs
tidak mencegah ini sama sekali. Namun, ada metode yang terbukti tidak akan mencemari tumpukan, kompiler tidak bisa membuktikannya. Sebelumnya, penelepon API semacam itu akan mendapatkan peringatan menjengkelkan yang sama sekali tidak ada gunanya tetapi harus ditekan di setiap situs panggilan. Sekarang penulis API dapat menekannya sekali di situs deklarasi.Namun, jika metode ini sebenarnya tidak aman, pengguna tidak akan lagi diperingatkan.
sumber
Saat Anda mendeklarasikan
public static <T> void foo(List<T>... bar)
kompiler mengubahnya menjadipublic static <T> void foo(List<T>[] bar)
lalu kepublic static void foo(List[] bar)
Bahaya kemudian muncul bahwa Anda akan keliru menetapkan nilai yang salah ke dalam daftar dan kompiler tidak akan memicu kesalahan apa pun. Misalnya, jika
T
aString
maka kode berikut akan dikompilasi tanpa kesalahan tetapi akan gagal saat runtime:Jika Anda meninjau metode untuk memastikan bahwa itu tidak mengandung kerentanan seperti itu maka Anda dapat membuat anotasi dengan
@SafeVarargs
untuk menekan peringatan. Untuk antarmuka, gunakan@SuppressWarnings("unchecked")
.Jika Anda mendapatkan pesan kesalahan ini:
dan Anda yakin bahwa penggunaan Anda aman maka Anda harus menggunakannya
@SuppressWarnings("varargs")
. Lihat Apakah @SafeVarargs anotasi yang sesuai untuk metode ini? dan https://stackoverflow.com/a/14252221/14731 untuk penjelasan yang bagus tentang jenis kesalahan kedua ini.Referensi:
sumber
Object[]
. Selama Anda tidak menyerahObject[]
, sepertinya Anda harus baik-baik saja.static <T> void bar(T...args) { ((Object[])args)[0] = "a"; }
. Lalu teleponbar(Arrays.asList(1,2));
.Object[]
mengapa kompiler memicu peringatan jika saya tidak melakukannya? Bagaimanapun, seharusnya cukup mudah untuk memeriksa ini pada waktu kompilasi (jika saya tidak meneruskannya ke fungsi lain dengan tanda tangan yang serupa, dalam hal ini fungsi lainnya harus memicu peringatan). Saya tidak percaya ini benar-benar inti dari peringatan ("Anda aman jika Anda tidak melemparkan"), dan saya masih tidak mengerti dalam hal ini saya baik-baik saja.bar(Integer...args)
). Jadi apa gunanya peringatan ini?@SafeVarargs
tidak mencegah hal itu terjadi, namun itu mengamanatkan bahwa kompiler lebih ketat ketika mengkompilasi kode yang menggunakannya.http://docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs.html menjelaskan hal ini lebih detail.
Heap polusi adalah ketika Anda mendapatkan
ClassCastException
saat melakukan operasi pada antarmuka generik dan berisi jenis lain dari yang dinyatakan.sumber
Ketika Anda menggunakan varargs, itu bisa menghasilkan pembuatan
Object[]
untuk menampung argumen.Karena lolos analisis, JIT dapat mengoptimalkan pembuatan array ini. (Salah satu dari beberapa kali saya menemukannya melakukannya) Tidak dijamin akan dioptimalkan, tetapi saya tidak akan khawatir tentang hal itu kecuali jika Anda melihat ada masalah di profil memori Anda.
AFAIK
@SafeVarargs
menekan peringatan oleh kompiler dan tidak mengubah perilaku JIT.sumber
@SafeVarargs
.Alasannya adalah karena varargs memberikan opsi untuk dipanggil dengan array objek non-parametrized. Jadi jika tipe Anda adalah List <A> ..., itu juga bisa disebut dengan tipe List [] non-varargs.
Berikut ini sebuah contoh:
Seperti yang Anda lihat Daftar [] b dapat berisi semua jenis konsumen, namun kode ini mengkompilasi. Jika Anda menggunakan varargs, maka Anda baik-baik saja, tetapi jika Anda menggunakan definisi metode setelah type-erasure - void test (List []) - maka kompiler tidak akan memeriksa tipe parameter templat. @SafeVarargs akan menekan peringatan ini.
sumber