2011-09-05 18 views
9

tengo superclase como:¿Por qué obtengo los métodos de la clase base por reflexión cuando la subclase los anula?

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

    public T getValue(){ 
    return null; 
    } 
} 

entonces tengo aa derivación específica

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

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

En la reflexión sobre MyClassImpl como:

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

puedo obtener tanto la implementación de la superclase java.lang.Object getValue(), void setValue(java.lang.Object) y java.lang.String getValue(), void setValue(java.lang.String).

De acuerdo con la documentación de Java de Class.getDeclaredMethods() vis-a-saber

Devuelve una matriz de objetos Método que reflejan todos los métodos declarados por la clase o interfaz que representa este objeto Class. Esto incluye acceso público, protegido, predeterminado (paquete) y métodos privados, pero excluye métodos heredados. Los elementos en la matriz devuelta no están ordenados y no están en ningún orden particular. Este método devuelve una matriz de longitud 0 si la clase o interfaz no declara ningún método, o si este objeto Clase representa un tipo primitivo, una clase de matriz o nulo. El método de inicialización de clase <clinit> no está incluido en la matriz devuelta. Si la clase declara múltiples métodos miembros públicos con los mismos tipos de parámetros, todos se incluyen en la matriz devuelta.

¿Por qué estoy recibiendo la implementación de super tipo? ¿Hay algo que me falta?

La razón por la que necesito esto es que invoco de manera reflexiva setValue en la implementación de la clase base, que he agregado algunos comentarios de anotación especiales y, por supuesto, restricciones adicionales.

+1

Puede haber un duplicado de http: // stackoverflow.com/questions/5756081/java-generics-reflection –

+1

@RC: No veo cómo podría ser un duplicado de esa pregunta. –

+0

@RC esto no es un duplicado exacto – amod

Respuesta

13

Es porque la clase compilada realmente hace declara setValue(Object). Ese método se lanzará a String, y luego llamará al método fuertemente tipado. Del mismo modo, getValue(Object) llama al getValue(String).

Básicamente esto es necesario porque la JVM no sabe realmente sobre los genéricos (al menos no de una manera profunda): para anular el método de la superclase a nivel de JVM, debe tener la misma firma.

Tener un vistazo a la clase con javap -c MyclassImp verá los métodos sintéticos adicionales:

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

Tenga en cuenta que 'Method.isSynthetic()' devolverá 'true' para aquellos métodos generados que toman/devuelven' Object'. Esa es una buena manera de distinguir esos métodos de los "reales". –

+0

¿Este comportamiento del compilador está documentado en alguna parte? –

+0

@Ryan: No sé, me temo. Mirando brevemente el JLS, no puedo verlo, aunque este tipo de situación se menciona en algunos lugares. –

1

Como Jon había dicho antes, información de tipo se pierde en tiempo de ejecución para los genéricos.

Por lo tanto, siempre que use genéricos, el compilador coloca todos los métodos heredados "genéricos" en la subclase. Lo mismo no es cierto con un código no genérico.

Acabo de comprobar: cuando eliminé el código genérico relacionado (la parte <T>) de la superclase y el código de reflexión me dio exactamente dos métodos en la subclase aunque los invalide. Implica que la documentación debería haber sido un poco explícita para el código genérico.

+0

Estrictamente hablando, esos métodos no están ahí debido a los genéricos (como habrás notado). Están ahí porque los métodos usan la covarianza del tipo de devolución (es decir, la clase secundaria devuelve un valor más específico que el tipo base). Es * más a menudo * utilizado en combinación con medicamentos genéricos, pero se puede usar de manera independiente. –

+0

¡Sí! Acabo de verificar. – Santosh

+0

sí, he verificado todos los escenarios, donde anulo en forma genérica y explícita. con forma genérica, solo tengo dos métodos, con covarianza, noté los dos métodos adicionales y están marcados como sintéticos – maress

Cuestiones relacionadas