我刚刚发现了这个,因为从Java 7升级到Java 8时,我的一个单元测试失败了。单元测试调用了一种方法,该方法尝试在子类上注释的方法上尝试查找注释,但使用不同的方法返回类型。为什么isAnnotationPresent在Java 7和Java 8之间的工作方式不同?
在Java 7中,isAnnotationPresent
似乎只能找到注释,如果它们真的在代码中声明的话。在Java 8中,isAnnotationPresent
似乎包含在子类中声明的注释。
为了说明这一点,我创建了一个简单的(??)测试类IAPTest(用于IsAnnotationPresentTest)。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class IAPTest {
@Retention(RetentionPolicy.RUNTIME)
public static @interface Anno {
}
public static interface I {
}
public static interface IE extends I {
}
public static class A {
protected I method() {
return null;
}
}
public static class B extends A {
@Anno
protected IE method() {
return null;
}
}
public static void main(String[] args) {
for (Method method : B.class.getDeclaredMethods()) {
if (method.getName().equals("method") && I.class.equals(method.getReturnType())) {
System.out.println(method.isAnnotationPresent(Anno.class));
}
}
}
}
在最新的Java 7(1.7.0_79在写作时),这种方法打印 “假”。在最新的Java 8(写作时为1.8.0_66)中,此方法打印出“true”。我会直觉地期望它打印“错误”。
这是为什么?这是否表明Java中存在错误或者Java如何工作?
EDIT:只是为了示出的确切命令我用来复制本(与IAPTest.java目录相同上面的代码块):
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>
嗯,这为我打印'false':Eclipse Mars 4.5.1,JDK 1.8.0_51。 – Tunaki
你为什么认为注释“是在儿童课堂上申报的”?你在'B'中注解了方法,并且你正在搜索'B'的*声明的方法*,而没有其他的东西。没有涉及的子类。 – Holger
@Holger当我搜索'B'的声明方法时,我发现了两种方法。一个方法表示子类的方法,一个方法表示父类的方法。你可以从返回类型中看出来。 'B.class.getDeclaredMethods()。length == 2'在Java 7和8上。因为我正在检查返回类型以确保父类方法是被引用的方法(返回类型是'I'而不是'IE'),'A'中的方法没有注解,但只有子类“B”中的注释。 – Kidburla