2011-09-05 9 views
9

Ho classe super come:Perché ottengo i metodi della classe base tramite riflessione quando la sottoclasse sovrascrive?

class MyClass<T> { 
    public void setValue(T value){ 
    //insert code 
    } 

    public T getValue(){ 
    return null; 
    } 
} 

poi ho aa derivazione specifica

class MyClassImp extends MyClass<String> { 
    @Override 
    public void setValue(String value){ 
    //insert code 
    } 

    @Override 
    public String getValue(){ 
    return null; 
    } 
} 

Su riflessione sul MyClassImpl come:

Class clazz = MyClassImpl.class; 
Method[] methods = clazz.getDeclaredMethods(); 

ottengo sia implementazione della superclasse java.lang.Object getValue(), void setValue(java.lang.Object) e java.lang.String getValue(), void setValue(java.lang.String).

Secondo la documentazione Java di Class.getDeclaredMethods() vis-a-viz

Restituisce un array di oggetti Method che riflettono tutti i metodi dichiarati dalla classe o interfaccia rappresentata da questo oggetto Class. Ciò include accesso pubblico, protetto, predefinito (pacchetto) e metodi privati, ma esclude i metodi ereditati. Gli elementi nella matrice restituita non sono ordinati e non sono in alcun ordine particolare. Questo metodo restituisce una matrice di lunghezza 0 se la classe o l'interfaccia non dichiara metodi, o se questo oggetto di classe rappresenta un tipo primitivo, una classe di matrice o vuoto. Il metodo di inizializzazione della classe <clinit> non è incluso nell'array restituito. Se la classe dichiara più metodi di membro pubblico con gli stessi tipi di parametri, sono tutti inclusi nell'array restituito.

Perché mi appare l'implementazione super-tipo? C'è qualcosa che mi manca?

Il motivo per cui ho bisogno di questo è che io invoco riflessivo setValue sulla implementazione della classe base, che ho aggiunto alcuni commenti annotazioni speciali e, naturalmente, ulteriori vincoli.

+1

Può essere un duplicato di http: // StackOverflow.it/questions/5756081/java-generics-reflection –

+1

@RC: Non vedo come potrebbe essere un duplicato di quella domanda. –

+0

@RC questo non è un duplicato esatto – amod

risposta

13

È perché la classe compilata in realtà fa dichiara setValue(Object). Questo metodo verrà eseguito il cast in String e quindi chiamerà il metodo fortemente tipizzato. Allo stesso modo getValue(Object) chiamate getValue(String).

Fondamentalmente ciò è necessario perché la JVM non conosce realmente i generici (almeno non in modo approfondito) - per sovrascrivere il metodo della superclasse a livello di JVM, deve avere la stessa firma.

Dai un'occhiata alla classe con javap -c MyclassImp vedrete i metodi sintetici aggiuntivi:

public java.lang.Object getValue(); 
    Code: 
    0: aload_0 
    1: invokevirtual #3; //Method getValue:()Ljava/lang/String; 
    4: areturn 

public void setValue(java.lang.Object); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: checkcast  #4; //class java/lang/String 
    5: invokevirtual #5; //Method setValue:(Ljava/lang/String;)V 
    8: return 

} 
+4

Si noti che 'Method.isSynthetic()' restituirà 'true' per quei metodi generati che accettano/restituiscono' Object'. Questo è un buon modo per distinguere quei metodi da quelli "reali". –

+0

Questo comportamento del compilatore è documentato da qualche parte? –

+0

@Ryan: non lo so, ho paura. Guardando brevemente il JLS, non riesco a vederlo, anche se questo tipo di situazione è menzionata in alcuni punti. –

1

Come Jon aveva detto in precedenza, informazioni sul tipo si perde in fase di esecuzione per i medicinali generici.

Così ogni volta che si usano i generici, il compilatore inserisce nella sottoclasse tutti quei metodi "generici" ereditati. Lo stesso non è vero con il codice non generico.

Ho appena controllato: quando ho rimosso il relativo codice generico (la parte <T>) dalla superclasse ed il codice di riflessione mi ha dato esattamente due metodi nella sottoclasse anche se li ignora. Implica che la documentazione avrebbe dovuto essere un po 'esplicita per il codice relativo al generico.

+0

Strettamente parlando quei metodi non sono lì a causa dei generici (come hai notato). Sono presenti perché i metodi utilizzano la covarianza del tipo restituito (ad esempio, la sottocategoria restituisce un valore più specifico del tipo base). Questo è * il più delle volte * usato in combinazione con i generici, ma può essere usato stand-alone. –

+0

Sì! Ho appena verificato. – Santosh

+0

sì ho verificato tutti gli scenari, in cui sovrascrivo in forma generica e modulo esplicito. con forma generica, ho solo due metodi, con covarianza, ho notato i due metodi aggiuntivi e sono contrassegnati come sintetici – maress

Problemi correlati