Używam Eclipse, aby pomóc mi oczyścić kod, aby poprawnie używać generycznych języków Java. W większości przypadków doskonale radzi sobie z wnioskami o typach, ale są pewne przypadki, w których wywnioskowany typ musi być tak ogólny, jak to tylko możliwe: Object. Ale wydaje się, że Eclipse daje mi możliwość wyboru między typem obiektu a typem „?”.
Jaka jest więc różnica między:
HashMap<String, ?> hash1;
i
HashMap<String, Object> hash2;
Odpowiedzi:
Wystąpienie
HashMap<String, String>
dopasowań,Map<String, ?>
ale nieMap<String, Object>
. Powiedzmy, że chcesz napisać metodę, która akceptuje mapy odString
s do wszystkiego: jeśli chcesz napisaćnie możesz dostarczyć
HashMap<String, String>
. Jeśli piszeszto działa!
Czasami błędnie rozumiane jest to, że
List<String>
nie jest to podtypList<Object>
. (AleString[]
w rzeczywistości jest to podtypObject[]
, jest to jeden z powodów, dla których typy generyczne i tablice nie mieszają się dobrze (tablice w Javie są kowariantne, typy generyczne nie są, są niezmienne )).Przykład: Jeśli chcesz napisać metodę, która akceptuje
List
s zInputStream
si podtypyInputStream
, napiszPrzy okazji: Efektywna Java Joshua Blocha to doskonałe źródło informacji, jeśli chcesz zrozumieć nie takie proste rzeczy w Javie. (Twoje pytanie powyżej jest również bardzo dobrze opisane w książce).
źródło
Innym sposobem myślenia o tym problemie jest to
jest równa
Połącz tę wiedzę z zasadą „Get and Put Principle” w sekcji (2.4) w dokumencie Java Generics and Collections :
i miejmy nadzieję, że dzika karta może zacząć mieć więcej sensu.
źródło
HashMap<String, ? extends Object>
więc zapobiega tylkonull
dodaniu do hasmapy?Łatwo to zrozumieć, jeśli pamiętasz, że
Collection<Object>
jest to tylko ogólna kolekcja, która zawiera obiekty typuObject
, aleCollection<?>
jest to nadtyp wszystkich typów kolekcji.źródło
Odpowiedzi powyżej kowariancji obejmują większość przypadków, ale pomijają jedną rzecz:
„?” zawiera „Obiekt” w hierarchii klas. Można powiedzieć, że String jest typem Object, a Object jest typem?. Nie wszystko pasuje do Object, ale wszystko pasuje?
źródło
Nie możesz bezpiecznie niczego włożyć
Map<String, ?>
, ponieważ nie wiesz, jakiego typu mają być wartości.Możesz umieścić dowolny obiekt w a
Map<String, Object>
, ponieważ wiadomo, że wartością jestObject
.źródło
Map<String,Integer>
. TylkoInteger
obiekty powinny umieszczać zapisane na mapie jako wartości. Ale ponieważ nie wiem typ wartości (to?
), nie wiem, czy jeśli to jest bezpieczne, aby zadzwonićput(key, "x")
,put(key, 0)
lub cokolwiek innego.Zadeklarowanie
hash1
jako aHashMap<String, ?>
dyktuje, że zmiennahash1
może przechowywać dowolną,HashMap
która ma kluczString
i dowolny typ wartości.Wszystkie powyższe są ważne, ponieważ zmienna
map
może przechowywać dowolną z tych map skrótów. Ta zmienna nie obchodzi, jaki jest typ wartości, jaki zawiera hashmap.Posiadanie wieloznaczny nie nie , jednak pozwala umieścić każdy rodzaj obiektu na mapie. w rzeczywistości, z powyższą mapą hashującą, nie możesz nic do niej wstawić używając
map
zmiennej:Wszystkie powyższe wywołania metod spowodują błąd w czasie kompilacji, ponieważ Java nie wie, jaki jest typ wartości HashMap wewnątrz
map
.Nadal możesz pobrać wartość z mapy skrótów. Chociaż „nie znasz typu wartości” (ponieważ nie wiesz, jaki typ mapy skrótów znajduje się w zmiennej), możesz powiedzieć, że wszystko jest podklasą,
Object
a więc cokolwiek wyjdziesz z mapy będzie typu Object:Powyższy blok kodu wypisze 10 na konsoli.
Aby zakończyć, użyj
HashMap
znaku wieloznacznego, gdy nie obchodzi Cię (tj. Nie ma znaczenia), jakie są typyHashMap
, na przykład:W przeciwnym razie określ potrzebne typy:
W powyższej metodzie musielibyśmy wiedzieć, że klucz mapy to a
Character
, w przeciwnym razie nie wiedzielibyśmy, jakiego typu użyć, aby uzyskać z niego wartości. Wszystkie obiekty mają jednaktoString()
metodę, więc mapa może mieć dowolny typ obiektu dla swoich wartości. Nadal możemy wydrukować wartości.źródło