mis*_*ico 4 annotations static-members java-8
我正在尝试注释中的静态字段,并且遇到了我不了解的问题。
我使用以下代码:
@a
public class myAnnotMinimal {
public static void main(String[] args) {
System.out.println(myAnnotMinimal.class.getAnnotations().length);
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface a {
Consumer<Integer> f1 = a -> {return;}; // -> 0
//Consumer<Integer> f2 = new B(); //-> 1
//Consumer<Integer> f3 = C::eat; //-> 1
//int f4 = 5; //->1
//Supplier<Integer> f5 = ()->5; //->1
}
class B implements Consumer<Integer> {
@Override
public void accept(Integer t) {
}
}
class C{
public static void eat(Integer t){
}
}
Run Code Online (Sandbox Code Playgroud)
现在,运行此命令时,我希望可以打印“ 1”,但是我得到的输出是“ 0”。当我删除f1字段并取消注释其他(f2-f5)字段时,输出为'1'。在我看来,这几乎像个虫子。我有什么想念的吗?我在Linux上使用jdk1.8.0_66。
由于这看起来像JDK中的错误,因此我提交了错误报告。到目前为止,错误报告已被接受。参见http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8147585。
这是JRE注释处理中的错误,或更准确地说,它的代码没有正确更新以适应新的语言功能,尽管可以理解的是,并未考虑使用这种用法。
注释不应该提供实用方法,声明常量(即隐式字段)的public static final功能不应滥用来添加带有代码的函数。
该错误的原因是某些Java语言构造在幕后产生了综合方法。字段初始化器可以<clinit>在字节码级别将代码添加到静态方法中,这是反射已知并忽略的,因此不会出现问题。这就是为什么Consumer<Integer> f2 = new B();可以工作的原因(就像在Java 8之前一样),创建是在此类初始化方法内进行的。请注意,将int f4 = 5;创建一个编译时常量,该常量根本不需要初始化代码。
但是,lambda表达式被编译为合成方法,尽管它们是private,但显然已被运行时Annotation实现忽略,但是会检查其是否与标准注释方法相符。
这就是为什么Supplier<Integer> f5 = ()->5;不会产生任何问题的原因,合成方法顺便遵循了注释方法模式,因为它没有参数并且返回值。相反,Consumer<Integer> f1 = i->System.out.println(i);被编译为具有一个参数和void返回类型的合成方法。这似乎导致注释处理工具拒绝该注释为无效(不报告它)。
相反,大多数方法引用都不需要合成辅助方法,因为它们直接指向目标方法,因此Consumer<Integer> f3 = C::eat;不会造成任何问题。您可以通过更改的声明证实这种模式f1来Consumer<Integer> f1 = System.out::println;,而在语义等同,问题消失了,因为现在有注释中的类文件中没有得罪合成方法。
尽管这确实是一个错误,但是当Java语言在注释字段中接受lambda表达式时,JRE实现应赶上来处理这种情况的时间,我强烈建议您不要以这种方式向注释类型添加代码。保存单个实用程序类不值得那种代码味道。还请记住,与普通实用程序方法相比,这会增加运行时开销。
| 归档时间: |
|
| 查看次数: |
3264 次 |
| 最近记录: |