我剛剛發現了這個,因爲從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