Java运行时保留批注在早期Java版本中的兼容性
我想在我的代码中使用来自Java 8的Java运行时保留批注在早期Java版本中的兼容性,java,maven,annotations,runtime,Java,Maven,Annotations,Runtime,我想在我的代码中使用来自Java 8的@functional接口,但我希望能够使用Java 6生成的类文件。我想我应该将源版本设置为1.8,目标版本设置为1.6 我将使用@functioninterface仅用于文档,但我注意到它有@Retention(RetentionPolicy.RUNTIME)。如果没有人使用该注释,它会导致问题吗 如果有人在运行时迭代我的对象的注释,是否会导致缺少类异常?但是如果这是真的,Google Guava如何能够提供一个Maven,这意味着在运行时Guava中也
@functional接口
,但我希望能够使用Java 6生成的类文件。我想我应该将源版本设置为1.8
,目标版本设置为1.6
我将使用@functioninterface
仅用于文档,但我注意到它有@Retention(RetentionPolicy.RUNTIME)
。如果没有人使用该注释,它会导致问题吗
如果有人在运行时迭代我的对象的注释,是否会导致缺少类异常?但是如果这是真的,Google Guava如何能够提供一个Maven
,这意味着在运行时Guava中也缺少javax.annotation.Nonnull
等注释,而不会引起问题
让我用另一种方式问:如果我在我的项目中使用GoogleGuava,但不包含JSR305依赖项,那么如果我在代码上使用反射,我真的会有出错的风险吗?如果是,会发生什么错误?如果不会发生错误,那么类似地,如果不需要类,我可以使用Java版本
1.8
编译的源代码中的@FunctionInterface
注释,但针对版本1.6
,而不存在任何运行时错误的风险吗?(或者更确切地说,不需要加载),类在运行时是否不存在并不重要。运行时注释通常也有相同的问题,因为如果它们在运行时保留,通常意味着有基于它们的逻辑,这意味着它们的类也被加载
但是@functioninterface
没有运行时逻辑,所以。。。
显然不是出于任何特别令人信服的原因,只是它的一个副作用也被记录在案
因此,如果您想确保如果有人(或者更可能的工具(我不是指“工具”,比如同事))决定枚举类中的注释,那么您需要在预处理时删除注释
我想我应该[设置]源版本为1.8
,目标版本为1.6
实际上,不可能为较旧的JVM目标版本编译较新源版本的Java源文件。如果-source
版本高于-target
版本,Oracles和OpenJDK将拒绝编译尝试。(然而,我找不到一个规范否认这一点,即使没有提到这一点。)javac
s交叉编译功能的唯一想法是,即使使用较新的JDK进行编译,您也可以为旧的1.6jvm编译旧的,例如1.6java文件
您所描述的问题就是这种情况的原因。由于Java使用的是一种延迟依赖项加载,编译器无法保证在运行时为所有依赖项提供适当的类。这也适用于标准库
但是,有一些(非官方)工具可以将较新的源代码习惯用法或字节码编译为较旧的字节码版本。但这不适用于标准库。如果你想使用较新的类,你必须自己提供它们。为此,标准库的特定部分有一些后台端口
特别是关于您的注释问题:
我无法找到任何可靠的规范,说明如果JVM遇到无法检索类文件的带注释的构造,应该/可能会发生什么情况(我搜索了)。但是,我在
注释是一种标记,它将信息与程序构造相关联,但在运行时不起作用
从
此语句表示注释(存在或不存在)不应影响JVM的执行。因此,由于缺少注释而导致的异常(如NoClassDefFoundError
)与此相反
最后,虽然答案是,但我发现了更具体的说法:
二进制形式的注释可能在运行时通过JavaSE平台的反射库可用,也可能不可用
从
及
添加或删除注释不会影响Java编程语言中程序二进制表示的正确链接
从
这非常清楚地表明,缺少注释将不会导致错误,相反,如果通过反射检查,将被忽略。
如果您提供了一个带有Java 1.8标准库注释的类,并且该类将(以某种方式)在Java 1.6 JVM上执行,而该注释并不存在,那么该规范拒绝生成任何错误
我编写的以下测试也支持这一点:(注意反射的用法)
如果编译,它将生成一个Test.class
和一个TestAnno.class
。执行时,程序输出:
@TestAnno()
因为这是应用于
Test
的一个注释。现在,如果TestAnno.class
被删除,而没有对Test.class
进行任何修改(这是指字节码中带有LTestAnno;
序列的TestAnno
)再次执行Test
,它只是不输出任何内容。因此,我的JVM确实忽略了缺少的注释,并且不会生成任何错误或异常(在Linux上使用OpenJDK 1.8.0131版进行测试).您阅读了链接吗?它明确指出您需要添加JSR305实现,以便javax.annotation。运行时不缺少Nonnull
。因此,如果在运行时缺少functional接口且需要加载,则可以
@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 {
}