为什么isAnnotationPresent在Java 7和Java 8之间的工作方式不同?

为什么isAnnotationPresent在Java 7和Java 8之间的工作方式不同?,java,reflection,annotations,java-8,java-7,Java,Reflection,Annotations,Java 8,Java 7,今天,当我的一个单元测试因为从Java7升级到Java8而失败时,我才发现了这一点。单元测试调用一个方法,该方法尝试查找在子类上注释但返回类型不同的方法上的注释 在Java7中,isAnnotationPresent似乎只有在注释真正在代码中声明时才能找到它们。在Java8中,isAnnotationPresent似乎包含在子类中声明的注释 为了说明这一点,我创建了一个简单的(?)测试类IAPTest(用于IsAnnotationPresentTest) 在最新的Java7(编写本文时为1.7.

今天,当我的一个单元测试因为从Java7升级到Java8而失败时,我才发现了这一点。单元测试调用一个方法,该方法尝试查找在子类上注释但返回类型不同的方法上的注释

在Java7中,
isAnnotationPresent
似乎只有在注释真正在代码中声明时才能找到它们。在Java8中,
isAnnotationPresent
似乎包含在子类中声明的注释

为了说明这一点,我创建了一个简单的(?)测试类IAPTest(用于IsAnnotationPresentTest)

在最新的Java7(编写本文时为1.7.079)上,此方法打印“false”。在最新的Java8(编写本文时为1.8.066)上,此方法打印“true”。我直觉上希望它打印“false”

为什么会这样?这是否表明Java中存在缺陷或Java工作方式的预期变化

编辑:仅显示我用于复制此命令的确切命令(在与上面代码块相同的带有IAPTest.java的目录中):


我相信这与报告中提到的一个变化有关

从本版本开始,参数和方法注释将复制到 合成桥接方法。此修复意味着现在对于以下程序:

@Target(value = {ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME) @interface ParamAnnotation {}  
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @interface MethodAnnotation {}  
abstract class T<A,B> {
    B m(A a){
        return null;
    }  
}    
class CovariantReturnType extends T<Integer, Integer> {
    @MethodAnnotation
    Integer m(@ParamAnnotation Integer i) {
        return i;
    }

    public class VisibilityChange extends CovariantReturnType {}   
}  
@Target(值={ElementType.PARAMETER})
@保留(RetentionPolicy.RUNTIME)@interface ParamAnnotation{}
@目标(值={ElementType.METHOD})
@保留(RetentionPolicy.RUNTIME)@interface MethodAnnotation{}
抽象类T{
B、m(A){
返回null;
}  
}    
类协变类型扩展了T{
@方法注释
整数m(@param注释整数i){
返回i;
}
公共类VisibilityChange扩展了类型{}
}  
每个生成的桥接方法都将具有 它重定向到的方法。参数注释也将被复制。 此行为的更改可能会影响某些注释或处理器 通常,任何使用注释的应用程序


返回
I
而不是
IE
的第二个方法是生成的合成方法,因为重写方法中的返回类型比超类中的返回类型窄。请注意,如果没有收缩返回类型,则它不会出现在声明的方法列表中。所以我认为这不是一个bug,而是一个故意的改变。

Hmm,这为我打印了
false
:EclipseMars4.5.1,JDK1.8.0\u51。为什么你认为注释“是在子类中声明的”?您已经在
B
中对该方法进行了注释,并且正在搜索
B
中声明的方法,没有其他内容。没有涉及任何子类。@Holger当我搜索
B
的声明方法时,我找到了两个方法。一个方法表示子类上的方法,另一个表示父类上的方法。从退货类型可以看出这一点B.class.getDeclaredMethods().length==2。因为我正在检查返回类型以确保父类方法是被引用的方法(返回类型是
I
,而不是
IE
),所以
A
中的方法没有注释,只有子类
B
@Tunaki中的注释,我刚刚用JDK版本测试过(build 1.8.0_51-b16)我得到了“true”。我直接运行Java(不是通过Eclipse)@Holger我没有说
B
有子类(子类).
A
有子类。返回的方法是父类的合成方法。我也从来没有说过我不相信你我正在查看的方法没有在
B
中声明。我同意你的看法。我不知道你为什么对我生气,但不管怎样,我的问题现在已经得到了回答。回答很好!你不仅提供了用推理、文档引用和修复单元测试以在Java 8上工作的方法告诉我-我只需要使用
isSynthetic
。谢谢!
C:\test-isannotationpresent>del *.class

C:\test-isannotationpresent>set JAVA_HOME=C:\nma\Toolsets\AJB1\OracleJDK\jdk1.8.0_66

C:\test-isannotationpresent>set PATH=%PATH%;C:\nma\Toolsets\AJB1\OracleJDK\jdk1.8.0_66\bin

C:\test-isannotationpresent>java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

C:\test-isannotationpresent>javac IAPTest.java

C:\test-isannotationpresent>java IAPTest
true

C:\test-isannotationpresent>
@Target(value = {ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME) @interface ParamAnnotation {}  
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @interface MethodAnnotation {}  
abstract class T<A,B> {
    B m(A a){
        return null;
    }  
}    
class CovariantReturnType extends T<Integer, Integer> {
    @MethodAnnotation
    Integer m(@ParamAnnotation Integer i) {
        return i;
    }

    public class VisibilityChange extends CovariantReturnType {}   
}