Dalam file konteks aplikasi musim semi saya, saya memiliki sesuatu seperti:
<util:map id="someMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
<entry key="some_key" value="some value" />
<entry key="some_key_2" value="some value" />
</util:map>
Di kelas java, implementasinya terlihat seperti:
private Map<String, String> someMap = new HashMap<String, String>();
someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
Di Eclipse, saya melihat peringatan yang mengatakan:
Jenis keamanan: Pemain yang tidak dicentang dari Object ke HashMap
Apa kesalahan yang telah aku perbuat? Bagaimana cara mengatasi masalah ini?
java
spring
type-safety
unchecked
DragonBorn
sumber
sumber
Jawaban:
Pertama-tama, Anda membuang-buang memori dengan
HashMap
panggilan kreasi baru . Baris kedua Anda sama sekali mengabaikan referensi untuk hashmap yang dibuat ini, membuatnya kemudian tersedia untuk pengumpul sampah. Jadi, jangan lakukan itu, gunakan:Kedua, kompiler mengeluh bahwa Anda melemparkan objek ke a
HashMap
tanpa memeriksa apakah itu aHashMap
. Tetapi, bahkan jika Anda melakukannya:Anda mungkin masih mendapatkan peringatan ini. Masalahnya adalah,
getBean
pengembalianObject
, jadi tidak diketahui apa jenisnya. Mengubahnya secaraHashMap
langsung tidak akan menyebabkan masalah dengan kasus kedua (dan mungkin tidak akan ada peringatan dalam kasus pertama, saya tidak yakin seberapa hebatnya kompiler Java dengan peringatan untuk Java 5). Namun, Anda mengubahnya menjadi aHashMap<String, String>
.HashMaps benar-benar peta yang mengambil objek sebagai kunci dan memiliki objek sebagai nilai,
HashMap<Object, Object>
jika Anda mau. Dengan demikian, tidak ada jaminan bahwa ketika Anda mendapatkan kacang Anda itu dapat direpresentasikan sebagaiHashMap<String, String>
karena Anda dapat memilikiHashMap<Date, Calendar>
karena representasi non-generik yang dikembalikan dapat memiliki objek apa pun.Jika kode dikompilasi, dan Anda dapat mengeksekusi
String value = map.get("thisString");
tanpa kesalahan, jangan khawatir tentang peringatan ini. Tetapi jika peta tidak sepenuhnya dari kunci string ke nilai string, Anda akan mendapatkanClassCastException
saat runtime, karena obat generik tidak dapat memblokir ini terjadi dalam kasus ini.sumber
Masalahnya adalah bahwa pemeran adalah pemeriksaan runtime - tetapi karena jenis penghapusan, saat runtime sebenarnya tidak ada perbedaan antara
HashMap<String,String>
danHashMap<Foo,Bar>
untuk yang lainFoo
danBar
.Gunakan
@SuppressWarnings("unchecked")
dan tahan hidung Anda. Oh, dan kampanye untuk obat generik yang diperbarui di Jawa :)sumber
Seperti yang ditunjukkan oleh pesan di atas, Daftar tidak dapat dibedakan antara a
List<Object>
dan aList<String>
atauList<Integer>
.Saya telah memecahkan pesan kesalahan ini untuk masalah yang serupa:
dengan yang berikut ini:
Penjelasan: Konversi tipe pertama memverifikasi bahwa objek adalah Daftar tanpa memperhatikan tipe yang ada di dalamnya (karena kami tidak dapat memverifikasi tipe internal di level Daftar). Konversi kedua sekarang diperlukan karena kompiler hanya tahu Daftar berisi beberapa jenis objek. Ini memverifikasi jenis setiap objek dalam Daftar saat diakses.
sumber
Peringatan hanya itu. Sebuah peringatan. Terkadang peringatan tidak relevan, terkadang tidak. Mereka digunakan untuk menarik perhatian Anda pada sesuatu yang menurut kompiler bisa menjadi masalah, tetapi mungkin tidak.
Dalam hal pemain, itu selalu akan memberikan peringatan dalam kasus ini. Jika Anda benar-benar yakin bahwa para pemeran tertentu akan aman, maka Anda harus mempertimbangkan untuk menambahkan anotasi seperti ini (saya tidak yakin dengan sintaks) sebelum baris:
sumber
Anda menerima pesan ini karena getBean mengembalikan referensi Objek dan Anda memasukkannya ke jenis yang benar. Java 1.5 memberi Anda peringatan. Itulah sifat menggunakan Java 1.5 atau lebih baik dengan kode yang berfungsi seperti ini. Spring memiliki versi typesafe
pada daftar todo-nya.
sumber
Jika Anda benar-benar ingin menghilangkan peringatan, satu hal yang dapat Anda lakukan adalah membuat kelas yang memanjang dari kelas generik.
Misalnya, jika Anda mencoba menggunakannya
Anda dapat membuat kelas baru seperti itu
Lalu saat Anda menggunakannya
Kompiler TIDAK tahu apa jenis (tidak lagi generik), dan tidak akan ada peringatan. Ini mungkin tidak selalu menjadi solusi yang sempurna, beberapa mungkin berpendapat jenis ini mengalahkan tujuan kelas generik, tetapi Anda masih menggunakan kembali semua kode yang sama dari kelas generik, Anda hanya menyatakan pada waktu kompilasi jenis apa Anda ingin menggunakan.
sumber
Solusi untuk menghindari peringatan yang tidak dicentang:
sumber
Solusi lain, jika Anda sering menemukan objek yang sama dan tidak ingin membuang sampah sembarangan
@SupressWarnings("unchecked")
, buatlah metode dengan anotasi. Dengan cara ini Anda memusatkan para pemeran, dan semoga mengurangi kemungkinan kesalahan.sumber
Kode di bawah ini menyebabkan Jenis keamanan Peringatan
Map<String, Object> myInput = (Map<String, Object>) myRequest.get();
Buat Objek Peta baru tanpa menyebutkan parameter karena jenis objek yang disimpan dalam daftar tidak diverifikasi.
Langkah 1: Buat Peta sementara baru
Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();
Langkah 2: Instantiate the Map utama
Langkah 3: Iterasi Peta sementara dan atur nilainya ke dalam Peta utama
sumber
Di sini:
Map<String,String> someMap = (Map<String,String>)getApplicationContext().getBean("someMap");
Anda menggunakan metode lawas yang umumnya tidak ingin kita gunakan karena mengembalikan
Object
:Metode yang disukai untuk mendapatkan (untuk singleton) / membuat (untuk prototipe) kacang dari pabrik kacang adalah:
Menggunakannya seperti:
akan mengkompilasi tetapi masih dengan peringatan konversi yang tidak dicentang karena semua
Map
objek tidak harusMap<String, String>
objek.Tetapi
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
tidak cukup dalam kelas generik kacang seperti koleksi generik karena itu mengharuskan untuk menentukan lebih dari satu kelas sebagai parameter: tipe koleksi dan tipe generiknya.Dalam skenario semacam ini dan secara umum, pendekatan yang lebih baik adalah tidak menggunakan
BeanFactory
metode langsung tetapi membiarkan kerangka kerja untuk menyuntikkan kacang.Deklarasi kacang:
Injeksi kacang:
sumber