2009-03-24 11 views
102

Sto usando Eclipse per aiutarmi a ripulire del codice per utilizzare correttamente i generici Java. La maggior parte delle volte sta facendo un ottimo lavoro nel dedurre i tipi, ma ci sono alcuni casi in cui il tipo dedotto deve essere il più generico possibile: Object. Ma Eclipse sembra offrirmi un'opzione per scegliere tra un tipo di oggetto e un tipo di "?".Qual è la differenza? e Object in Java generics?

Allora, qual è la differenza tra:

HashMap<String, ?> hash1; 

e

HashMap<String, Object> hash2; 
+1

Vedere il tutorial ufficiale su [Wildcards] (http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html). Lo spiega bene e fornisce un esempio del perché è necessario semplicemente usando Object. –

risposta

103

Un'istanza di HashMap<String, String> partite Map<String, ?> ma non Map<String, Object>. Dire che si desidera scrivere un metodo che accetta le mappe da String s a qualsiasi cosa: Se volete scrivere

public void foobar(Map<String, Object> ms) { 
    ... 
} 

non si può fornire una HashMap<String, String>. Se scrivi

public void foobar(Map<String, ?> ms) { 
    ... 
} 

funziona!

Una cosa a volte fraintesa nei generici di Java è che List<String> non è un sottotipo di List<Object>. (Ma String[] è in realtà un sottotipo di Object[], questo è uno dei motivi per cui i generici e gli array non si combinano bene (gli array in Java sono covarianti, i generici no, sono invarianti)).

Esempio: Se vuoi scrivere un metodo che accetta List s di InputStream s e sottotipi di InputStream, devi scrivere

public void foobar(List<? extends InputStream> ms) { 
    ... 
} 

A proposito: Joshua Bloch's Effective Java è una risorsa eccellente quando si Mi piacerebbe capire le cose non così semplici in Java. (La tua domanda di cui sopra è anche trattata molto bene nel libro.)

+1

è il modo giusto per utilizzare ResponseEntity a livello di controller per tutte le funzioni del mio controller? – Purmarili

3

Non puoi mettere nulla in sicurezza nello Map<String, ?>, perché non sai che tipo di valori dovrebbero essere.

È possibile inserire qualsiasi oggetto in un Map<String, Object>, poiché il valore è noto come Object.

+0

"Non è possibile inserire nulla in modo sicuro in Map " False. PUOI, questo è il suo scopo. –

+0

Sbagliato, Ben. Fare questo genererà avvisi "non controllati". Lo scopo dei caratteri jolly è scrivere un codice che possa funzionare su qualsiasi tipo generico. – erickson

+1

Ben è sbagliato, l'unico valore che è possibile inserire in una raccolta di tipo è nullo, mentre è possibile inserire qualsiasi cosa in una raccolta di tipo . –

7

È facile capire se si ricorda che Collection<Object> è solo una raccolta generica che contiene oggetti di tipo Object, ma Collection<?> è un tipo eccellente di tutti i tipi di raccolte.

+1

C'è da dire che non è esattamente facile ;-), ma è giusto. –

23

Un altro modo di pensare a questo problema è che

HashMap<String, ?> hash1; 

è equivalente a

HashMap<String, ? extends Object> hash1; 

Coppia questa conoscenza con il "Get e Put Principio" nella sezione (2.4) da Java Generics and Collections:

The Get e Put Principio: utilizzare un estende jolly quando si ottiene solo valori di una struttura, utilizzare Super jolly quando si mette solo i valori in una struttura, e non usare un jolly quando entrambi si mettono e si mettono.

e la jolly può iniziare a dare più senso, si spera.

+0

Se "?" ti confonde, "? extends Object" probabilmente ti confonderà di più. Può essere. –

+0

Cercando di fornire "strumenti per pensare" per permettere di ragionare su questo argomento difficile. Fornite ulteriori informazioni sull'estensione dei caratteri jolly. –

+1

Grazie per le informazioni aggiuntive. Sto ancora digerendolo. :) – skiphoppy

1

Le risposte di cui sopra copertura di covarianza maggior parte dei casi, ma perdere una cosa: "?"

è comprensivo di "Oggetto" nella gerarchia di classi. Si potrebbe dire che String è un tipo di oggetto e Object è un tipo di?. Non tutto corrisponde a Object, ma tutto corrisponde?

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 
Problemi correlati