@Retention of Java 类型检查器注解

@Retention of Java type checker annotations

Java 8 种类型注释 (JSR 308) 允许类型检查器执行静态代码分析。例如,The Checker Framework 可以通过 @NonNull 注释检查可能的 nullness

各个项目定义自己的NonNull注解,例如:

对于此类注释,我希望 @interface 具有 @Retention(RetentionPolicy.CLASS),因为在运行时通常不需要它们。最重要的是,代码对各自的库没有任何运行时依赖性。

同时 org.eclipse.jdt.annotation.NonNull follows this approach, most other NonNull annotations, like javax.annotation.Nonnull (JSR 305) and org.checkerframework.checker.nullness.qual.NonNull itself, have @Retention(RetentionPolicy.RUNTIME)。这些注释中的 RetentionPolicy.RUNTIME 是否有任何特殊原因?


说明:Checker Framework 支持注释中的注释以实现向后兼容性。然而,使用 Java 8 中的那些只是为了避免运行时依赖性似乎是一个肮脏的 hack。

每个注释都有其用途!

javax.validation.constraints.NotNull

这个是bean validation规范定义的,用来在运行时进行非空检查,所以需要在运行时保留它来进行,比如一个form valdiation ...

@RetentionPolicy.SOURCE => 通常用于文档 @RetentionPocily.CLASS => 允许将一些信息提供给编译器而不是 JVM(例如,在编译期间执行代码生成) @RetentionPolicy.RUNTIME => 允许在 JVM 级别(因此在运行时)检索注释信息。

此致,

洛伊克

这是个好问题。

为了在编译时进行静态检查,CLASS 保留就足够了。请注意,SOURCE 保留是不够的,因为需要单独编译:当对 class 进行类型检查时,编译器需要读取其使用的库上的注释,并且单独编译的库可用于编译器仅作为 class 个文件。

注释设计者使用 RUNTIME 保留来允许工具执行 运行 时间操作。这可能包括检查注释(如 assert 语句)、动态加载代码的类型检查、强制转换和 instanceof 操作的检查、更精确地解析反射等等。如今这样的工具并不多,但注释设计者希望将来能容纳它们。

您曾说过 @Retention(RetentionPolicy.CLASS),"the code does not have any runtime dependencies on the respective library." 实际上 @Retention(RetentionPolicy.RUNTIME) 也是如此!看到这个堆栈溢出问题: Why doesn't a missing annotation cause a ClassNotFoundException at runtime?.

总而言之,在 运行 时,使用 CLASS 留存成本 space 可以忽略不计,可以在未来实现更多潜在用途,并且不会引入 运行-时间依赖性。

对于 Checker Framework,它提供 运行 次测试,例如 isRegex(String)。如果您的代码使用此类方法,您的代码将依赖于 Checker Framework 运行time 库(它比整个 Checker Framework 本身更小并且具有更宽松的许可)。