簡體   English   中英

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

[英]Why does isAnnotationPresent work differently between Java 7 and Java 8?

我剛剛發現這個,因為我的一個單元測試由於從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),此方法打印“false”。 在最新的Java 8(編寫本文時為1.8.0_66),此方法打印“true”。 我會直覺地期望它打印“假”。

為什么是這樣? 這是否表明Java中的錯誤或Java的工作方式有何變化?

編輯 :只是為了顯示我用來復制它的確切命令(在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>

我相信這與java 8兼容性指南中提到的更改有關

在此版本中,參數和方法注釋被復制到合成橋接方法。此修復意味着現在對於以下程序:

 @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 {} } 

每個生成的橋接方法都將具有重定向到的方法的所有注釋。 參數注釋也將被復制。 行為的這種改變可能會影響某些注釋處理器或通常任何使用注釋的應用程序。

返回I而不是IE的第二種方法是生成的合成方法,因為重寫方法中的返回類型比超類中的返回類型更窄。 請注意,如果您沒有縮小返回類型,則它不會出現在聲明的方法列表中。 所以我認為這不是一個錯誤,而是一個故意的改變。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM