2013-07-08 5 views
5

Ho una domanda per quanto riguarda i farmaci generici:dettaglio circa la wildcard "super" in generici Java

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

con Super è possibile creare un'istanza di un HashMap<Object,Object> per un <? super String>. Tuttavia, è possibile aggiungere solo oggetti che estendono String (in questo caso solo String stesso). Perché non vietano l'errore di compilazione così come accade con la wildcard extends. Voglio dire se una volta creato un Map <Object, Object> è possibile solo aggiungere stringhe .. perché non forzare a creare un Map<String, String> in primo luogo? (come accade con la wildcard extends)

Anche in questo caso conosco la differenza tra super e extends relativi ai generici. Vorrei solo conoscere i dettagli che ho menzionato.

Grazie in anticipo.

+1

Tuttavia Quindi è possibile aggiungere solo gli oggetti che si estende String (in questo caso solo stringa stessa) È possibile aggiungere CharSequences e oggetto, non oggetti che si estende String. – Nimajen

+0

@Nimajen è menzionato nella domanda. – Rollerball

+0

scusa, chiave sbagliata. Il mio commento è stato incompleto. – Nimajen

risposta

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

Dal Java Generics si basano sulla cancellazione del tipo, con questa linea non hai creato un MashMap<Object,Object>. Hai appena creato un'istanza della classe HashMap; i parametri di tipo vengono persi immediatamente dopo questa riga di codice e tutto ciò che rimane è il tipo della variabile mappa1, che non menziona nemmeno Object. Il tipo dell'espressione new è compatibile con l'assegnazione del tipo di mappa1 in modo che il compilatore consenta l'assegnazione.

In generale, i parametri di tipo utilizzati con new sono irrilevanti e per affrontare questo problema, Java 7 ha introdotto l'operatore diamante<>. Tutto ciò che conta davvero è il tipo di mappa1, che è Map<? super String, ? super String>; per quanto riguarda il resto del codice, questo è il tipo di mappa istanziata.

+0

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html Tuttavia, nel link in questione, dice: Rollerball

+0

Inoltre nel caso del carattere jolly "extends" avrebbe dovuto essere consentito anche. Non è possibile creare una HashMap se il riferimento è Mappa <. – Rollerball

+0

Ovviamente non lo è: 'Object' non estende' String'. –

0

Il problema che stai descrivendo non esiste. È perché il tuo riferimento è dichiarato come Map<? super String, ? super String>. Ma l'oggetto reale può contenere qualsiasi oggetto dal momento che è 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); 

lo stesso può essere descritto da un esempio migliore:

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

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

Non risponde alla mia domanda. Non voglio sapere una soluzione per questo. Mi piacerebbe solo sapere perché funziona così – Rollerball

+1

scusa, non è una soluzione, è una spiegazione. String è solo una classe ordinaria in Java. Il compilatore non si cura se è la tua classe personalizzata o java.lang.String. – Tala

2

Penso che tu sia stato buttato via perché hai scelto un tipo di raccolta. Le raccolte vengono utilizzate raramente come consumatori e quindi un limite inferiore (? super X) non viene inserito nei loro tipi di elementi. Un esempio più appropriato è il predicato.

Prendere in considerazione un metodo come <E> List<E> filter(List<? extends E> p, Predicate<? super E> p). Sarà necessario un elenco l e un predicato p e verrà restituito un nuovo elenco contenente tutti gli elementi di l che soddisfano p.

È possibile passare in un List<Integer> e un Predicate<Number> che è soddisfatto da tutti i multipli di 2.5. Il Predicate<Number> diventerebbe un Predicate<? super Integer>. In caso contrario, non è possibile richiamare il filtro come segue.

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

Usiamo List invece di Map per brevità.

In sostanza, significato pratico di extends e super possono essere definiti come segue:

  • List<? extends T> significa "un List è possibile ottenere T da"
  • List<? super T> significa "un List si può mettere T in"

Ora potete vedere che non c'è niente di speciale su extends - il comportamento dei extends e super è completamente simmetrica:

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>