2010-10-23 8 views
27

Dato:Perché compare "Tipo generico non valido per instanceof"?

public class C<T> { 
    private class D { 
     public boolean equals(Object o) { 
      if (!(o instanceof D)) // line 4 
       return false; 
      D other = (D)o;    // line 6 
      return i == other.i; 
     } 
     int i; 
    } 
} 

ottengo:

C.java:4: illegal generic type for instanceof 
      if (!(o instanceof D)) 
          ^

ho anche ottenere un "getto incontrollato" avvertimento circa la linea 6. Perché? Il o è non un tipo generico - è solo un semplice Object. Come posso implementare correttamente equals() controllando e rilasciando un'istanza di D?

Nota: Ovviamente, questo esempio di codice è una versione ridotta del mio codice effettivo. Le classi reali per C e D sono molto più grandi e D è una classe interna private di C utilizzata dalla relativa implementazione.

FYI: il vero D utilizza il parametro generico T.

+7

Hai provato * instanceof C.D * invece di * D * instanceof? –

+0

Ho appena notato che l'esempio dato * è * rotto. –

+0

@Evan: funziona. Ma perché è necessaria la qualifica? –

risposta

30

L'o non è un tipo generico - è solo un oggetto semplice.

Questo non è il problema. Il problema ... e la causa principale di entrambi gli errori di compilazione ... è che D è una classe generica. Ed è generico perché è una classe annidata non statica in una classe generica. Il suo nome completo sarà some.pkg.C<T>.D.

FYI: Il vero D fa utilizzare il parametro generico T.

E il fatto che si potrebbe fare uso di T è ciò che rende D una classe generica.

Il motivo per cui non è possibile utilizzare instanceof D o (D) è di tipo generico. Fondamentalmente, il runtime non è in grado di distinguere tra i tipi di (diciamo) C<String>.D e C<Integer>.D. E poiché non può farlo, non può determinare se instanceof D deve restituire true o false o se (D) deve avere successo o tirare ClassCastException.

Una soluzione sarebbe dichiarare D come statico. Ma questo non funzionerà con la tua "vera D", perché una classe statica non può utilizzare un parametro di tipo generico dalle classi che lo contengono. La tua "FYI" dice che lo fa.

Un'altra soluzione è quella di istanziare la classe esterna C passandogli il tipo effettivo di T come istanza java.lang.Class<T>. Quindi utilizzare questa istanza Class per implementare i controlli di tipo runtime e i cast come richiesto. Questo è probabilmente disordinato.

La terza soluzione è con attenzione analizzare il codice e determinare se è sicuro alle annotazioni @SuppressWarning per sopprimere gli avvertimenti "cast non sicuri" ecc.

Che tipo di cancellazione? 'o' è di tipo Object direttamente.

realtà Object è il tipo dichiarato della variabile o. L'oggetto effettivo molto probabilmente avrà un altro tipo, ed è quello di tipo che (se è un'istanza D per esempio) sarà stato sottoposto a cancellazione di tipo.

7

Se si crea la classe interna statica, il codice viene compilato correttamente.

Es:

private static class D{...} 

Leggi here per la differenza.

Si potrebbe anche provare o.getClass() != D.class (dopo la guardia contro o essere nullo, ovviamente)

+0

Conosco la differenza tra classi nidificate non statiche e statiche. In questo caso, ho bisogno di esso non statico. Se creo la classe nidificata statica, non posso fare uso del parametro generico T. –

+1

Che dire dei confronti o.getClass() e D.class? Non saprai che sono dello stesso tipo parametrizzato, ma non sono sicuro di poterlo fare comunque in modo affidabile con la cancellazione dei tipi. –

+0

Che tipo di cancellazione? 'o' è di tipo Object direttamente. –

3
D.class.isInstance(o) 

sembra funzionare qui.

6

@StephenC ha ragione, il problema è che D significa C<T>.D, che è un tipo parametrizzato. La soluzione è quella di utilizzare il tipo crudo o il tipo di carattere jolly-parametrizzato:

if (!(o instanceof C.D)) 

o

if (!(o instanceof C<?>.D)) 
Problemi correlati