[英]Java runtime retention annotations - annotation class required at compile time but not at runtime?
[英]Compatibility of a Java runtime retention annotation in previous Java versions
我想在我的代码中使用Java 8中的@FunctionalInterface
,但我希望能够将生成的类文件与Java 6一起使用。我认为我应该将源版本设置为1.8
,将目标版本设置为1.6
。
我将使用@FunctionalInterface
仅用于文档,但我注意到它有@Retention(RetentionPolicy.RUNTIME)
。 如果没有人使用该注释,它会导致问题吗?
如果有人在运行时迭代我的对象的注释,它是否会导致缺少类异常? 但是,如果这是真的,那么Google Guava如何声明JSR 305注释依赖关系以提供Maven <scope>
,这意味着在运行时,在Guava中, javax.annotation.Nonnull
等注释也会丢失。没有造成问题?
让我用另一种方式问:如果我在项目中使用Google Guava但不包含JSR 305依赖项,如果我对代码使用反射,我是否真的会冒一些错误? 如果是这样,会发生什么错误? 如果不会发生错误,那么类似地,我可以在使用Java版本1.8
编译的源代码中使用@FunctionalInterface
注释,但是针对版本1.6
而没有任何运行时错误的风险,即使使用反射也是如此?
我认为那时我应该[设置]源版本为
1.8
,目标版本为1.6
。
其实,这是不可能的编译更新的源代码版本的Java源文件为老版本的JVM版本的目标。 Oracles和OpenJDKs javac
将拒绝-source
版本高于-target
版本的编译尝试。 (但是,我找不到拒绝它的规范,即使手册没有提到它)。 javac
的交叉编译功能的唯一想法是,即使您使用较新的JDK进行编译,您仍可以为旧的1.6 JVM编译旧的1.6 Java文件。
您描述的问题是这样的原因。 由于Java使用了一种延迟依赖性加载,因此编译器无法保证在运行时对所有依赖项都有适当的类。 这也适用于标准库。
但是,有(非官方)工具可以将较新的源惯用法或字节代码编译为较旧的字节代码版本。 但这不适用于标准库。 如果你想使用更新的课程,你必须自己提供。 为此,标准库的特定部分存在一些后端口。
特别是关于您的注释问题:
如果JVM遇到无法检索类文件的带注释的构造(我搜索了Java虚拟机规范SE 8 ),我无法找到任何应该/可能发生的可靠规范。 但是,我在Java语言规范SE 8中找到了一些相关的参考:
注释是将信息与程序构造相关联的标记,但在运行时没有影响。
来自JLS 9.7
此语句反而表明注释(是否存在)不应对JVM的执行产生影响。 因此,由于缺少注释而导致的异常(例如NoClassDefFoundError
)更倾向于此。
最后,虽然这个问题的答案,我发现了更具体的陈述:
二进制形式中存在的注释可能在运行时通过Java SE平台的反射库提供,也可能不提供。
和
添加或删除注释对Java编程语言中程序的二进制表示的正确链接没有影响。
这非常明确地指出,缺少注释不会导致错误 ,但是如果通过反射检查则会被忽略。 如果你提供一个Java 1.8标准库注解注释的类,这将是(在某种程度上)上例如,Java 1.6 JVM执行如该注释是不存在,那么这个规格否认产生任何错误。
我写的以下测试也支持这一点:( 注意反射的用法)
@TestAnno
public class Test {
public static void main(String[] args) {
Annotation[] annos = Test.class.getAnnotations();
for (Annotation a : annos) {
System.out.println(a);
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnno {
}
如果编译,它会产生Test.class
和TestAnno.class
。 执行时程序输出:
@TestAnno()
因为这是应用于Test
的一个注释。 现在,如果TestAnno.class
而不以任何修改删除Test.class
(指TestAnno
与LTestAnno;
在字节码序列)和Test
再次被执行,它只是不输出任何东西 。 所以我的JVM确实忽略了缺少的注释,并且没有生成任何错误或异常(在Linux上使用OpenJDK版本1.8.0_131进行了测试)。
与任何类加载情况一样,如果不需要类(或者更确切地说,不需要加载),那么在运行时该类是否不存在并不重要。 运行时注释通常具有相同的问题,因为如果它们在运行时保留,通常意味着存在基于它们的逻辑,这意味着它们的类也被加载。
但@FunctionalInterface
没有运行时逻辑,所以... 为什么@FunctionalInterface有RUNTIME保留? 显然不是出于任何特别令人信服的理由,只是它的副作用也是@Documented
注释。
因此,如果你想确保没有潜在的问题,如果某人(或某些工具更可能(我不是指“工具”,如同事))决定列举你班级的注释,我想你需要在预处理时删除注释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.