2013-04-28 9 views
6

Ecco un esempio:Int.class.isInstance (Object) è una contraddizione?

public boolean check(Class<?> clazz, Object o) 
{ 
    return clazz.isInstance(o); 
} 

check(int.class, 7); // returns false 

Dal isInstance accetta un Object, non funzionerà con int, perché int è un tipo primitivo e ottiene autoboxed a Integer. Quindi è possibile scrivere un metodo di controllo generico? O dovrei assicurarmi che il clazz sia di tipo Class<? extends Object>?

+4

Invece di usare tag non molto significativi come 'int',' types' o anche 'isintance', dovresti taggare la domanda con la lingua che stai usando. Ciò attirerebbe più spettatori e quindi aumenta le possibilità di ricevere una risposta soddisfacente. –

+1

Sry, l'ho completamente dimenticato. ... Immagino che java sia diventato naturale per me: D – mike

+2

Hai letto [questa risposta] (http://stackoverflow.com/a/7083456/516433) ancora? – Lucas

risposta

6

Non tutte Class oggetti rappresentano tipi classi/di riferimento; ci sono anche gli oggetti Class che rappresentano i tipi primitivi. Ciò è utile perché nell'utilizzo della riflessione con campi e metodi, è spesso necessario specificare il loro tipo e può essere un tipo primitivo. Quindi, Class viene utilizzato per rappresentare tutti questi tipi di pre-generici.

Tuttavia, molti dei metodi della classe Class non hanno senso per i tipi primitivi. Ad esempio, è impossibile che un oggetto sia instanceof int. Pertanto, il metodo analogo .isInstance() restituirà sempre false. Poiché il parametro di questo metodo è il tipo Object, è semplicemente impossibile da un punto di vista linguistico per ciò che si passa in là per essere di un tipo primitivo.

Certo, in Java 5+ quando si passa un primitivo a un parametro di tipo Object, esso subisce autoboxing, ma il fatto che ha subito autoboxing significa che ciò che è stato passato è in realtà un riferimento a un oggetto. I tipi di riferimento e i tipi primitivi sono distinti. Un parametro è un tipo di riferimento o di tipo primitivo. Quindi non puoi scrivere un metodo che possa prendere un "riferimento o primitivo".

Cosa si può chiedere, nel tuo esempio, è da rilevare che l'oggetto è stato autoboxed da un primitivo, e confrontarlo con un tipo primitivo. Tuttavia, è impossibile rilevare se il chiamante lo ha automaticamente disattivato, poiché l'autoboxing è un'operazione completamente eseguita sul lato chiamante che avviene prima della chiamata.

Tuttavia, supponendo che è stata autoboxed, si sa che tipo dovrebbe essere andato. Se ti aspetti un int e viene autoboxato e passato al tuo metodo, dovrebbe essere un'istanza di Integer.Quindi, quello che potresti fare è, quando clazz rappresenta un tipo primitivo, invece di eseguire il controllo sulla sua classe wrapper. Pertanto, quando vede che clazz è int.class, sostituirlo con Integer.class e quindi eseguire il controllo. Si noti che in questo modo continua a non sapere se ciò che è stato passato come il parametro o è stato autoboxed.

+0

Ho fatto qualche ricerca, sembra che non ci sia un metodo generico per ottenere la classe wrapper di un tipo primitivo, o un modo generico per ottenere il campo TYPE di una classe wrapper. Credo di dover codificare una mappa e di eseguire una ricerca al riguardo. – mike

+1

@ mike Se ti capita di usare Guava, le maniglie di classe ['Primitive'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/primitives/Primitives.html) quei casi d'uso già. –

+0

Grazie, ma i metodi guava si basano anche su una mappa codificata. Ad ogni modo, ottime risposte e commenti qui, ho imparato molto! – mike

2

Non c'è int di classe in Java. La sua classe Integer. 7 viene convertito in Integer.valueOf(7) e int.class verrà convertito in Integer.class come da JLS.

Se p è il nome di un tipo primitivo, cerchiamo B essere il tipo di un espressione di tipo p dopo la conversione di pugilato. Quindi il tipo di p.class è Class<B>.

Poiché Integer è un oggetto di classe, mentre int è di tipo primitivo. Così, la maggior parte dei metodi di Class quali isInstance, isAssignableFrom ecc, che opera su oggetti non sono validi nel contesto int.class, quindi si vede che la contraddizione.

check(Integer.class, 7); 

dovrebbe dare il risultato previsto.

+0

Uso un modulo del metodo di controllo in un contesto di un setter generico, in cui estraggo le informazioni sul tipo dall'attributo per impostarlo e confrontarlo con il tipo di parametro del setter. Quindi dovrei proibire i tipi primitivi per gli attributi che voglio impostare? – mike

+0

Sarebbe utile mostrare il codice per questo setter generico. Se è come ' void setSomething (T theThing)', non sarai in grado di utilizzare direttamente le primitive in ogni caso - saranno sempre in modalità autoboxed, perché i tipi generici possono essere solo Oggetti, mai primitivi. – BeeOnRope

+0

Puoi vedere il codice in un'altra domanda che ho posto su SO http://stackoverflow.com/questions/16225623/how-to-avoid-getters-setters-in-classes-with-many-instance-variables – mike