2011-09-05 15 views
9

我有超类为:为什么在子类覆盖它们时通过反射来获取基类方法?

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

    public T getValue(){ 
    return null; 
    } 
} 

然后,我有机管局具体推导

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

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

在反思MyClassImpl为:

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

我得到两个超类实现java.lang.Object getValue()void setValue(java.lang.Object)java.lang.String getValue()void setValue(java.lang.String)

根据Class.getDeclaredMethods() VIS-A-即

的Java文档返回Method对象反映此Class对象所表示的类或接口声明的所有方法的一个数组。这包括公共,受保护,默认(包)访问和私有方法,但不包括继承的方法。返回的数组中的元素没有排序并且没有任何特定的顺序。如果类或接口不声明任何方法,或者此Class对象表示原始类型,数组类或void,则此方法返回长度为0的数组。类初始化方法<clinit>不包含在返回的数组中。如果类声明多个具有相同参数类型的公共成员方法,则它们都包含在返回的数组中。

为什么我得到超类型实现? 有什么我失踪?

我需要这个的原因是,我反思性地调用基类实现setValue,我添加了一些特殊的注释注释,当然还有其他限制。

+1

可能是http:// stackoverflow的副本。com/questions/5756081/java-generics-reflection – 2011-09-05 05:59:41

+1

@RC:我不明白它可能是这个问题的重复。 –

+0

@RC这不是一个完全重复的 – amod

回答

13

这是因为编译的类实际上是确实声明setValue(Object)。该方法将转换为String,然后调用强类型方法。同样getValue(Object)调用getValue(String)

基本上这是必需的,因为JVM并不真正了解泛型(至少不是深入了解) - 为了覆盖JVM级别的超类方法,它必须具有相同的签名。

看一看与javap -c MyclassImp类,你会看到额外的合成方法:

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

请注意,对于那些生成/返回Object的方法,Method.isSynthetic()将返回true。这是将这些方法与“真实”方法区分开来的好方法。 –

+0

此编译器行为是否记录在某处? –

+0

@瑞恩:我不知道,我很害怕。纵观JLS,我看不到它 - 尽管在几个地方提到了这种情况。 –

1

由于乔恩曾在此前表示,类型信息在运行时丢失了泛型

因此,无论何时使用泛型,编译器都会将所有这些“泛型”继承方法放在子类中。非通用代码也是如此。

我刚刚检查:当我从超类中删除通用相关代码(<T>部分)时,反射代码给了我正好两个子类中的方法,即使它覆盖了它们。这意味着该文档应该对通用相关的代码有点明确。

+0

严格地说,这些方法并不存在,因为泛型(正如您已经注意到的)。他们在那里,因为方法使用返回类型协方差(即子类返回比基类型更具体的值)。这是*最常用的*与泛型组合使用,但可以单独使用。 –

+0

是的!我刚刚证实。 – Santosh

+0

是的,我已经验证了所有场景,其中我以通用形式和显式形式进行覆盖。与通用形式,我只有两种方法,协方差,我注意到两个额外的方法,他们被标记为合成 – maress

相关问题