Saya menggunakan Eclipse untuk membantu saya membersihkan beberapa kode untuk menggunakan Java generics dengan benar. Sebagian besar waktu itu melakukan pekerjaan yang sangat baik dalam menyimpulkan tipe, tetapi ada beberapa kasus di mana tipe yang disimpulkan harus generik mungkin: Objek. Tapi Eclipse sepertinya memberiku pilihan untuk memilih antara tipe Object dan tipe '?'.
Jadi apa perbedaan antara:
HashMap<String, ?> hash1;
dan
HashMap<String, Object> hash2;
Jawaban:
Contoh
HashMap<String, String>
pertandinganMap<String, ?>
tetapi tidakMap<String, Object>
. Katakanlah Anda ingin menulis metode yang menerima peta dariString
s ke apapun: Jika Anda mau menulispublic void foobar(Map<String, Object> ms) { ... }
Anda tidak dapat menyediakan
HashMap<String, String>
. Jika Anda menulispublic void foobar(Map<String, ?> ms) { ... }
berhasil!
Suatu hal yang terkadang disalahpahami dalam generik Java adalah bahwa
List<String>
itu bukan subtipe dariList<Object>
. (TetapiString[]
sebenarnya adalah subtipe dariObject[]
, itulah salah satu alasan mengapa generik dan array tidak bercampur dengan baik. (Array di Java adalah kovarian, bukan generik, mereka tidak berubah )).Contoh: Jika Anda ingin menulis metode yang menerima
List
s dariInputStream
dan subtipeInputStream
, Anda akan menulispublic void foobar(List<? extends InputStream> ms) { ... }
Ngomong-ngomong: Java Efektif Joshua Bloch adalah sumber yang sangat baik ketika Anda ingin memahami hal-hal yang tidak sesederhana itu di Java. (Pertanyaan Anda di atas juga dibahas dengan sangat baik dalam buku ini.)
sumber
Cara lain untuk memikirkan masalah ini adalah itu
setara dengan
Gabungkan pengetahuan ini dengan "Prinsip Dapatkan dan Taruh" di bagian (2.4) dari Java Generics and Collections :
dan kartu liar mungkin mulai lebih masuk akal, semoga.
sumber
HashMap<String, ? extends Object>
jadi hanya mencegahnull
untuk ditambahkan di hashmap?Sangat mudah untuk dipahami jika Anda mengingat bahwa
Collection<Object>
itu hanyalah koleksi umum yang berisi objek bertipeObject
, tetapiCollection<?>
merupakan tipe super dari semua jenis koleksi.sumber
Jawaban di atas kovarians mencakup sebagian besar kasus tetapi melewatkan satu hal:
"?" termasuk "Objek" dalam hierarki kelas. Bisa dikatakan bahwa String adalah tipe Object dan Object adalah tipe?. Tidak semuanya cocok dengan Object, tapi semuanya cocok?.
int test1(List<?> l) { return l.size(); } int test2(List<Object> l) { return l.size(); } List<?> l1 = Lists.newArrayList(); List<Object> l2 = Lists.newArrayList(); test1(l1); // compiles because any list will work test1(l2); // compiles because any list will work test2(l1); // fails because a ? might not be an Object test2(l2); // compiled because Object matches Object
sumber
Anda tidak dapat memasukkan apa pun dengan aman
Map<String, ?>
, karena Anda tidak tahu jenis nilai yang seharusnya.Anda dapat memasukkan objek apa pun ke dalam a
Map<String, Object>
, karena nilainya dikenal sebagaiObject
.sumber
Map<String,Integer>
. HanyaInteger
objek yang harus disimpan di peta sebagai nilai. Tapi karena Anda tidak tahu jenis nilai (itu?
), Anda tidak tahu apakah apakah itu aman untuk memanggilput(key, "x")
,put(key, 0)
, atau apa pun.Mendeklarasikan
hash1
sebagaiHashMap<String, ?>
menentukan bahwa variabelhash1
dapat menampung apa sajaHashMap
yang memiliki kunciString
dan jenis nilai apa pun.HashMap<String, ?> map; map = new HashMap<String, Integer>(); map = new HashMap<String, Object>(); map = new HashMap<String, String>();
Semua hal di atas valid, karena variabel
map
dapat menyimpan peta hash mana pun. Variabel itu tidak peduli apa jenis Nilai, dari hashmap yang dimilikinya.Memiliki wildcard tidak tidak , bagaimanapun, membiarkan Anda menempatkan jenis objek ke dalam peta Anda. Faktanya, dengan hash map di atas, Anda tidak dapat memasukkan apa pun ke dalamnya menggunakan
map
variabel:map.put("A", new Integer(0)); map.put("B", new Object()); map.put("C", "Some String");
Semua panggilan metode di atas akan menghasilkan kesalahan waktu kompilasi karena Java tidak tahu apa tipe Nilai dari HashMap di dalamnya
map
.Anda masih bisa mendapatkan nilai dari peta hash. Meskipun Anda "tidak tahu jenis nilainya", (karena Anda tidak tahu jenis peta hash apa yang ada di dalam variabel Anda), Anda dapat mengatakan bahwa semuanya adalah subkelas dari
Object
dan, jadi, apa pun yang Anda dapatkan dari peta akan menjadi tipe Object:HashMap<String, Integer> myMap = new HashMap<>();// This variable is used to put things into the map. myMap.put("ABC", 10); HashMap<String, ?> map = myMap; Object output = map.get("ABC");// Valid code; Object is the superclass of everything, (including whatever is stored our hash map). System.out.println(output);
Blok kode di atas akan mencetak 10 ke konsol.
Jadi, untuk menyelesaikannya, gunakan a
HashMap
with wildcard bila Anda tidak peduli (tidak masalah) apa jenisnyaHashMap
, misalnya:public static void printHashMapSize(Map<?, ?> anyMap) { // This code doesn't care what type of HashMap is inside anyMap. System.out.println(anyMap.size()); }
Jika tidak, tentukan jenis yang Anda butuhkan:
public void printAThroughZ(Map<Character, ?> anyCharacterMap) { for (int i = 'A'; i <= 'Z'; i++) System.out.println(anyCharacterMap.get((char) i)); }
Dalam metode di atas, kita perlu tahu bahwa kunci Map adalah a
Character
, jika tidak, kita tidak akan tahu tipe apa yang digunakan untuk mendapatkan nilai darinya. Semua objek memilikitoString()
metode, bagaimanapun, sehingga peta dapat memiliki tipe objek apa pun untuk nilainya. Kami masih bisa mencetak nilainya.sumber