2012-10-09 4 views
6

Eventuali duplicati:
What are the reasons why Map.get(Object key) is not (fully) generic
Why does Java's TreeSet<E> remove(Object) not take an EPerché HashSet <E> non limitare il tipo di argomento per E in contiene() e rimuovere()

Perché HashSet non limita il tipo di argomento a E qui:

public boolean contains(Object o) 
public boolean remove(Object o) 

come avviene per add()

public boolean add(E e) 

intendo se il compilatore è far rispettare che solo oggetti di tipo E sono stati aggiunti, allora l'insieme non può contenere/rimuovere qualsiasi altro tipo

+0

'add' aggiunge nuovo elemento alla lista quindi è necessario assicurarsi che sia il tipo giusto. –

risposta

4

La differenza è che l'aggiunta deve essere di tipo sicuro per preservare l'integrità della raccolta, mentre il controllo/rimozione degli articoli può essere "indulgente al tipo" senza il rischio di danneggiare la sicurezza del tipo della raccolta. In altre parole, se si aggiunge un elemento di un tipo errato, il set non sarà più valido; d'altra parte, se si verifica la presenza di un elemento di un tipo sbagliato, si ottiene semplicemente un false. Lo stesso vale per remove: se si passa un elemento di un tipo incompatibile, non sarà nel set +, quindi la rimozione sarà un no-op.


+ A meno che non lo si inserisca tramite un hack che sfrutta la cancellazione dei tipi.

+1

Se si passa un elemento di un tipo incompatibile, l'elemento _ può ancora essere_ nell'insieme - vedere la mia risposta. – npe

+1

@npe Sì, il buon vecchio hack di cancellazione di tipo! Ho aggiornato la risposta per citare la possibilità, anche se il nucleo della risposta rimane lo stesso: la distinzione tra metodi generici e non generici dell'interfaccia è stata fatta lungo le linee dannose/innocue. – dasblinkenlight

+0

+ A meno che non lo si inserisca attraverso un hack che sfrutta la cancellazione del tipo o semplicemente è uguale a un elemento nel set ... (vedi la mia risposta per i dettagli). – DaveFar

2

quindi il set non può contenere/rimuovere nessun altro tipo

Certo che può. Leggi type erasure o invia il tuo a non-generic HashSet e aggiungi un oggetto che non sia di tipo E ad esso.

Partenza di questo codice:

Integer testInt = new Integer(3); 

// First, create a generic set of strings 
HashSet<String> set = new HashSet<String>(); 
set.add("abc"); 

// Then make it non-generic and add an integer to it 
((HashSet) set).add(testInt); 

// Now your set-of-strings contains an integer! 
System.out.println(set); // prints: [abc, 3] 

// Remove the integer 
set.remove(testInt); 
System.out.println(set); // prints: [abc] 

La ragione di questa stranezza è che le informazioni dei tipi generici viene cancellata in fase di esecuzione e il set diventa un semplice insieme di oggetti.

+0

'HashSet ' puoi aggiungere un elemento con quello? –

+0

No, non puoi. Correggerò la risposta – npe

+0

Quando si utilizza il? jolly come parametro generico, stai dicendo al compilatore che hai un'istanza, e il parametro generico è un valore, ma non sai cosa. Pertanto, è intrinsecamente pericoloso chiamare qualsiasi metodo su quell'oggetto che utilizza quel parametro generico. Prendi HashSet come esempio. potresti costruire HashSet ma assegnarlo a HashSet come fa il compilatore a sapere che tipo è realmente il parametro? Risposta: non può Lo stesso vale anche se il carattere jolly è limitato (ad es. HashSet ) – Matt

0

Non si aggiunge nulla al set con questi due metodi, quindi il parametro type non deve essere vincolato. Se il tipo non corrisponde, i metodi possono solo restituire false.

2

I parametri di contains e remove non possono essere limitati a E perché si dovrebbe essere in grado di fornire solo oggetti uguali, il che è molto utile. Più precisamente, l'API di HashSet.remove dice:

... Più formalmente, rimuove un elemento e tale che (? O == null e == null: o.equals (e)), se questo insieme contiene un tale elemento.

Object.equals assume come parametro Object, che è anche molto utile per consentire l'uguaglianza tra diversi tipi.

Pertanto, per abilitare la funzionalità più generale di contains e remove (sulle classi di equivalenza anziché solo sull'identità dell'oggetto), devono assumere come parametro Object.


Esempio:

HashSet<ArrayList<String>> set = new HashSet<ArrayList<String>>(); 
    ArrayList<String> list = new ArrayList<String>(); 
    list.add("foo"); 
    LinkedList<String> equalList = new LinkedList<String>(); 
    equalList.add("foo"); 
    set.add(list); 

    System.out.println(list.equals(equalList)); // prints: true 
    System.out.println(set.contains(equalList)); // prints: true 

    System.out.println(set); // prints: [[foo]] 
    set.remove(equalList); 
    System.out.println(set); // prints: [[]] 
Problemi correlati