为什么 isAnnotationPresent 在 Java 7 和 Java 8 之间的工作方式不同? [英] Why does isAnnotationPresent work differently between Java 7 and Java 8?

查看:30
本文介绍了为什么 isAnnotationPresent 在 Java 7 和 Java 8 之间的工作方式不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天刚刚发现了这一点,因为我的一个单元测试由于从 Java 7 升级到 Java 8 而失败.单元测试调用一个方法,该方法试图在一个方法上找到一个注释,该方法在子类上进行了注释,但带有不同的返回类型.

I just discovered this today when one of my unit tests failed because of upgrading from Java 7 to Java 8. The unit test calls a method which tries to find an annotation on a method which is annotated on a child class but with a different return type.

在 Java 7 中,isAnnotationPresent 似乎只找到真正在代码中声明的注解.在 Java 8 中,isAnnotationPresent 似乎包含在子类中声明的注释.

In Java 7, isAnnotationPresent seems to only find annotations if they were really declared in code. In Java 8, isAnnotationPresent seems to include annotations that were declared in child classes.

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

To illustrate this I created a simple (??) test class IAPTest (for 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".我直觉上希望它打印false".

On the latest Java 7 (1.7.0_79 at time of writing), this method prints "false". On the latest Java 8 (1.8.0_66 at time of writing), this method prints "true". I would intuitively expect it to print "false".

这是为什么?这是否表示 Java 中存在错误或 Java 工作方式的预期变化?

Why is this? Does this indicate a bug in Java or an intended change in how Java works?

编辑:只是为了显示我用来复制它的确切命令(在 IAPTest.java 与上面的代码块相同的目录中):

EDIT: Just to show the exact commands I used to replicate this (in a directory with IAPTest.java identical to the code block above):

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 兼容性指南

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

As of this release, parameter and method annotations are copied to synthetic bridge methods.This fix implies that now for programs like:

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

每个生成的桥接方法都会有所有的注解它重定向到的方法.参数注释也将被复制.这种行为变化可能会影响某些注释处理器或通常是任何使用注释的应用程序.

Each generated bridge method will have all the annotations of the method it redirects to. Parameter annotations will also be copied. This change in the behavior may impact some annotations processor or in general any application that use the annotations.

返回 I 而不是 IE 的第二种方法是生成的合成方法,因为覆盖方法中的返回类型比超类中的返回类型更窄.请注意,如果您没有缩小返回类型,则它不会出现在声明的方法列表中.所以我认为这不是一个错误,而是一个刻意的改变.

The second method that returns an I instead of an IE is a synthetic method generated because you have a narrower return type in the overridden method than in the super class. Note that it's not present in the list of declared methods if you don't have a narrowing return type. So I think this is not a bug, but a deliberate change.

这篇关于为什么 isAnnotationPresent 在 Java 7 和 Java 8 之间的工作方式不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆