2013-07-08 14 views
5

Mam pytanie dotyczące leków generycznych:Szczegóły o „super” zamiennika w rodzajowych java

Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>(); 

z super jest to możliwe do instancji HashMap<Object,Object> dla <? super String>. Można jednak dodawać tylko obiekty, które rozszerzają ciąg (w tym przypadku tylko sam ciąg). Dlaczego nie zabraniają przez błąd kompilacji, tak jak dzieje się to w przypadku wieloznacznika extends. Mam na myśli, że po utworzeniu Map <Object, Object> możliwe jest tylko dodanie ciągów. Dlaczego nie zmusić do stworzenia Map<String, String>? (jak to się dzieje w przypadku wieloznacznika extends)

Znów znam różnicę między super a extends dotyczącą leków generycznych. Chciałbym tylko poznać szczegóły, o których wyżej wspomniałem.

Z góry dziękuję.

+1

Jednak wtedy można dodać tylko obiekty, które rozciąga String (w tym przypadku tylko sam łańcuch) Możesz dodać CharSequences i obiektu, a nie objets która rozciąga String. – Nimajen

+0

@Nimajen jest wspomniany w pytaniu. – Rollerball

+0

Przepraszam, zły klucz. Mój komentarz był niekompletny. – Nimajen

Odpowiedz

2
Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>(); 

Ponieważ Java rodzajowych są w oparciu o typ usunięcia z tej linii nie utworzyłeś MashMap<Object,Object>. Właśnie stworzyłeś instancję klasy HashMap; Parametry typu giną natychmiast po tym wierszu kodu, a wszystko, co pozostaje, jest typem zmiennej mappa1, która nawet nie wspomina o Object. Typ wyrażenia new jest zgodny z typem mappa1, więc kompilator zezwala na przypisanie.

Ogólnie parametry rodzaju stosowanych z new są nieistotne i do rozwiązania tego problemu, Java 7 wprowadziła operatora diament<>. Wszystko, co naprawdę ma znaczenie, to typ mappa1, który jest Map<? super String, ? super String>; jeśli chodzi o resztę kodu, jest to typ tworzonej mapy.

+0

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html Jednak w tym linku jest napisane: Rollerball

+0

Ponadto w przypadku symbolu wieloznacznego "extends" powinno być również dozwolone. Intead nie jest możliwe stworzenie HashMap , jeśli odwołanie jest Map <. – Rollerball

+0

Oczywiście nie jest: 'Object' nie rozszerza' String'. –

0

Problem, który opisujesz, nie istnieje. Dzieje się tak dlatego, że Twoje odwołanie jest zadeklarowane jako Map<? super String, ? super String>. Ale rzeczywisty obiekt może posiadać żadnych przedmiotów, ponieważ jest to HashMap<Object,Object>

Map<? super String, ? super String> mappa1 = new HashMap<Object,Object>(); 
map1.put("", ""); 

//you can put only string to map1 

//but you can do this 
Map map2 = map1; 
map2.put(23, 234); 

samo można opisać za pomocą lepszego przykładu:

String a = "a". 
a.length(); // legal. 

Object b = a; 
b.length() // compilation error 
+0

To nie odpowiada na moje pytanie. Nie chcę wiedzieć o obejściu tego problemu. Chciałbym tylko wiedzieć, dlaczego to działa tak, jak to – Rollerball

+1

przepraszam, To nie jest obejście, to wyjaśnienie. String jest po prostu zwykłą klasą w Javie. Kompilator nie dba o to, czy jest to Twoja klasa niestandardowa czy java.lang.String. – Tala

2

Myślę, że jesteś wyrzucony, ponieważ wybrałeś typ kolekcji. Kolekcje rzadko są używane jako konsumenci, dlatego dolna granica (? super X) nie jest umieszczana na ich typach elementów. Bardziej odpowiednim przykładem jest predykat.

Rozważmy metodę taką jak <E> List<E> filter(List<? extends E> p, Predicate<? super E> p). Spowoduje to pobranie listy l i predykatu p i zwrócenie nowej listy zawierającej wszystkie elementy l, które spełniają p.

Można podać List<Integer> i Predicate<Number>, które są spełnione przez wszystkie wielokrotności 2.5. Numer Predicate<Number> zostanie zmieniony na Predicate<? super Integer>. Jeśli nie, nie można wywołać filtra w następujący sposób.

List<Integer> x = filter(Arrays.asList(1,5,8,10), Predicates.multipleOf(2.5)); 
5

Użyjmy List zamiast Map dla zwięzłości.

Zasadniczo, praktyczne znaczenie extends i super można zdefiniować następująco:

  • List<? extends T> oznacza "List można uzyskać T z"
  • List<? super T> oznacza "List można umieścić T do"

Teraz możesz zobaczyć, że nie ma nic specjalnego o extends - zachowanie extends i super jest całkowicie symetryczny:

List<? extends Object> a = new ArrayList<String>(); // Valid, you can get an Object from List<String> 
List<? extends String> b = new ArrayList<Object>(); // Invalid, there is no guarantee that List<Object> contains only Strings 

List<? super String> a = new ArrayList<Object>(); // Valid, you can put a String into List<Object> 
List<? super Object> b = new ArrayList<String>(); // Invalid, you cannot put arbitrary Object into List<String>