Domanda

Se io dichiaro una classe come un campo:

Class fooClass;

Eclipse mi dà l'avvertimento:

  

Class è un tipo grezzo. I riferimenti a   tipo generico di classe dovrebbe essere   parametrizzata

Che cosa significa questo in pratica? e perché sono ho esortato a farlo? Se chiedo Eclipse per un "quick fix" mi dà:

Class<?> fooClass;

che non sembra aggiungere molto valore, ma non dà più un avvertimento.

EDIT: Perché è classe generica? La prego di dare un esempio di parametrizzazione, cioè ci potrebbe essere un valido utilizzo di qualcosa di diverso da <?>?

EDIT: WOW! Non avevo capito la profondità di questo. Ho anche guardato il Puzzler Java ed è certamente mi spaventava sulle trappole per orsi. Quindi sarò sempre usare

Class<MyString> myStringClass = MyString.class;

anziché

Class myStringClass = MyString.class;

(Ma dopo aver utilizzato Java da un giorno, non ho davvero notato quando Class diventato generico);

Nota: Ho @oxbow_lakes accettata come questo ha un senso per me, ma è chiaramente una zona molto complicata. Esorto tutti i programmatori di utilizzare la Class<MyString> specifica piuttosto che Class. E Class<?> è molto più sicuro di Class.

È stato utile?

Soluzione

Tipi prime e Unbounded caratteri jolly

Nessuna delle risposte precedenti hanno veramente affrontato il motivo per cui si dovrebbe preferire Class<?> sopra Class, come sulla faccia di esso, l'ex sembra offrire più informazioni rispetto al secondo.

La ragione è che, il tipo grezzo , cioè Class, impedisce al compilatore di effettuare controlli di tipo generico. Cioè, se si utilizzano tipi prime, si Subvert il tipo di sistema . Ad esempio:

public void foo(Class<String> c) { System.out.println(c); }

può essere chiamato questa convenzione (lo farà sia in fase di compilazione e run):

Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)

ma non da:

Class<?> w = Integer.class
foo(w); //WILL NOT COMPILE (RIGHTLY SO!)

Per sempre utilizzando il modulo non-prime, anche se è necessario utilizzare ? perché non si può sapere qual è il parametro di tipo è (o è delimitata da), si consente più pienamente che se il compilatore alla ragione circa la correttezza del proprio programma si è utilizzato tipi prime.


Perché i Tipi prime a tutti?

Il Java Language Specification dice:

  

L'uso di tipi prime è consentito solo come una concessione alla compatibilità di codice legacy

Si dovrebbe sempre evitare di loro. Il ? jolly illimitata è probabilmente meglio descritta altrove, ma essenzialmente mezzi "Questo è parametrizzata su un certo tipo, ma non so (o cura) che cosa è" . Questo non è lo stesso di tipi prime , che sono un abominio e non esistono in altre lingue con i generici, come Scala .


Perché è classe parametrica?

Bene, ecco un caso d'uso. Supponiamo che io sono un po 'interfaccia di servizio:

public interface FooService

E voglio iniettare un'implementazione di essa, utilizzando una proprietà di sistema per definire la classe da utilizzare.

Class<?> c = Class.forName(System.getProperty("foo.service"));

Non so a questo punto che la mia classe, è del corretto tipo :

//next line throws ClassCastException if c is not of a compatible type
Class<? extends FooService> f = c.asSubclass(FooService.class); 

Ora posso istanziare un FooService:

FooService s = f.newInstance(); //no cast

Altri suggerimenti

  

che non sembra aggiungere molto valore   ma non dà più un avvertimento.

Hai ragione. Ma questo potrebbe aggiungere valore:

Class<FooClass> fooClass;

o, se più appropriato:

Class<? extends FooClass> fooClass;

o

Class<FooInterface> fooClass;

Come per i farmaci generici in generale, si può migliorare la sicurezza di tipo specificando che tipo di classe che si desidera la variabile da stiva. L'avvertimento contro i tipi prime è solo scopo di catturare i pezzi di codice in cui questo potenziale non viene utilizzato. Dichiarando Class<?> si sta fondamentalmente dicendo "questo è significa per accogliere ogni tipo di classe".

Poiché, dal JDK 5, Class ha ora hanno tipo parametrico, che marchi Class un oggetto generico. Ciò è necessario (dopo l'introduzione dei generici) per il compilatore di fare il tipo di controllo (in fase di compilazione, naturalmente).

Class<?> significa una "classe di ignoto", dove ? è un generici jolly . Significa che fooClass di tipo Class<?> accetta un Class il cui tipo corrisponde a qualsiasi cosa.

Esempio tipico:

Class<?> classUnknown = null;
classUnknown = ArrayList.class; //This compiles.

È possibile, in modo efficace, a patto di un tipo parametrico per essere più precisi, per esempio:.

Class<ArrayList> = ArrayList.class;

PS Tenete a mente, che Class<List> listClass = ArrayList.class; non sarà la compilazione (anche se ArrayList è di List), ma (come Mark Peters menzionato sul commento) Class<? extends List> listClass = ArrayList.class; fa compilazione (grazie al jolly).

Il Javadoc della classe Classe dà qualche idea sul perché esistono parametri di tipo per questa classe:

  

T - il tipo della classe modellato da   questo oggetto Class. Ad esempio, la   tipo di String.class è Class<String>.   Utilizzare Class<?> se l'essere di classe   modellato è sconosciuta.

L'uso di questo tipo di parametro non è così ovvio, ma un rapido sguardo al codice sorgente della classe, indica il motivo per cui il parametro di tipo a volte è necessario. Prendere in considerazione l'attuazione del metodo newInstance:

    public T newInstance() 
        throws InstantiationException, IllegalAccessException
    {
    if (System.getSecurityManager() != null) {
        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
    }
    return newInstance0();
    }

Se non si è notato, il tipo di oggetto restituito da questo metodo è che il parametro di tipo. Ciò è utile nel codice che utilizza un sacco di riflessione, e dove si vorrebbe essere molto attenti per assicurare che gli oggetti del tipo giusto sono in fase di un'istanza.

Considerando l'esempio nella domanda, se l'istanza della classe è stato invece dichiarato come:

Class<String> fooClass;
Class<Integer> barClass;
String aString;

, allora, è quasi impossibile avere il seguente codice per compilare:

aString = barClass.newInstance();

In breve, se avete intenzione di lavorare con le gerarchie di classi e si desidera imporre severi controlli orari di compilazione per garantire che il codice non ha bisogno di eseguire un sacco di controlli instanceof, allora è meglio specificare la tipo della classe che si desidera utilizzare. Specificando ? consente tutti i tipi, ma non ci sarebbe casi in cui avrete bisogno di essere più specifico.

Perché l'utilizzo di tipi prime invece di tipi parametrici ha molte insidie.

Uno dei quali è che se si utilizza un tipo grezzo, tutti i farmaci generici sulla classe si perdono. Anche quelli definiti per-metodo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top