Saya baru saja menemukan @SafeVarargs
penjelasan java . Googling untuk apa yang membuat fungsi variadic di Java tidak aman membuat saya agak bingung (heap poisoning? Terhapus jenis?), Jadi saya ingin tahu beberapa hal:
Apa yang membuat fungsi Java variadic tidak aman dalam
@SafeVarargs
arti (lebih disukai dijelaskan dalam bentuk contoh mendalam)?Mengapa anotasi ini diserahkan pada kebijaksanaan programmer? Bukankah ini sesuatu yang harus bisa diperiksa oleh kompiler?
Apakah ada standar yang harus dipatuhi untuk memastikan fungsinya benar-benar aman? Jika tidak, apa praktik terbaik untuk memastikannya?
retType myMethod(Arg first, Arg... others)
. Jika Anda tidak menentukanfirst
, array kosong diperbolehkan, dan Anda mungkin memiliki metode dengan nama yang sama dengan tipe pengembalian yang sama tanpa argumen, yang berarti JVM akan kesulitan menentukan metode mana yang harus dipanggil.Jawaban:
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:
Di Jawa, vararg adalah gula sintaksis yang mengalami "penulisan ulang" sederhana pada waktu kompilasi: parameter tipe vararg
X...
diubah menjadi parameter tipeX[]
; dan setiap kali panggilan dilakukan ke metode varargs ini, kompiler mengumpulkan semua "argumen variabel" yang masuk dalam parameter varargs, dan membuat array sepertinew X[] { ...(arguments go here)... }
.Ini bekerja dengan baik ketika jenis varargs seperti beton
String...
. Ketika itu adalah variabel tipe sepertiT...
, itu juga berfungsi ketikaT
dikenal sebagai tipe konkret untuk panggilan itu. misalnya jika metode di atas adalah bagian dari sebuah kelasFoo<T>
, dan Anda memilikiFoo<String>
referensi, kemudian memanggilfoo
di atasnya akan baik-baik saja karena kita tahuT
adalahString
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 menggunakannew Object[] { ... }
(di siniObject
adalah batas atasT
; jika ada batas atas adalah sesuatu yang berbeda, itu akan menjadi bukanObject
), dan kemudian memberi Anda peringatan kompiler.Jadi apa yang salah dengan menciptakan
new Object[]
bukannew 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:
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:
Masalahnya di sini adalah bahwa kita bergantung pada jenis yang
args
akan digunakanT[]
untuk mengembalikannyaT[]
. Tetapi sebenarnya jenis argumen saat runtime bukan turunan dariT[]
.3) Jika metode Anda memiliki argumen tipe
T...
(di mana T adalah parameter tipe apa pun), maka:T
T[]
Hal-hal yang bergantung pada tipe runtime dari array meliputi: mengembalikannya sebagai tipe
T[]
, meneruskannya sebagai argumen ke parameter tipeT[]
, mendapatkan tipe array menggunakan.getClass()
, meneruskannya ke metode yang bergantung pada tipe runtime dari array, sepertiList.toArray()
danArrays.copyOf()
, dll.2) Perbedaan yang saya sebutkan di atas terlalu rumit untuk dibedakan secara otomatis.
sumber
FOO<T extends Something>
apakah aman untuk mengembalikan T [] metode varargs sebagai arraySomthing
s?@SafeVarargs
adalah ketika satu-satunya hal yang Anda lakukan dengan array adalah meneruskannya ke metode lain yang sudah begitu dijelaskan (misalnya: Saya sering menemukan diri saya menulis metode vararg yang ada untuk mengubah argumen mereka ke daftar menggunakanArrays.asList(...)
dan meneruskannya ke metode lain; kasus seperti itu selalu dapat dijelaskan dengan@SafeVarargs
karenaArrays.asList
memiliki anotasi).@SafeVarargs
kecuali metode inistatic
ataufinal
, karena kalau tidak bisa ditimpa dalam kelas turunan dengan sesuatu yang tidak aman.private
metode yang juga tidak dapat diganti.Untuk praktik terbaik, pertimbangkan ini.
Jika Anda memiliki ini:
Ubah ke ini:
Saya menemukan bahwa saya biasanya hanya menambahkan varargs agar lebih nyaman bagi penelepon saya. Hampir selalu akan lebih mudah bagi implementasi internal saya untuk menggunakan a
List<>
. Jadi untuk mendukungArrays.asList()
dan memastikan tidak ada cara saya bisa memperkenalkan Heap Pollution, inilah yang saya lakukan.Saya tahu ini hanya menjawab # 3 Anda. newacct telah memberikan jawaban yang bagus untuk # 1 dan # 2 di atas, dan saya tidak memiliki reputasi yang cukup untuk meninggalkan ini sebagai komentar. : P
sumber