RetentionPolicy.CLASS
和RetentionPolicy.RUNTIME
之间的实际区别是什么?
看起来两者都被记录到字节码中,而且两者在运行时都可以访问。
RetentionPolicy.CLASS
和RetentionPolicy.RUNTIME
之间的实际区别是什么?
看起来两者都被记录到字节码中,而且两者在运行时都可以访问。
无论哪种方式,都可以在运行时访问。
这并不是javadoc所说的:
RUNTIME: 编译器将注释记录在类文件中,并且保留在运行时的VM中,因此可以通过反射读取。
CLASS: 编译器将注释记录在类文件中,但不需要在运行时的VM中保留。
实际上,我不知道任何使用CLASS
的用例。它只有在编程方式读取字节码而不是通过类加载器API时才有用,但那是一个非常专门的情况,我不知道为什么你不会只使用RUNTIME
。
具有讽刺意味的是,默认行为是CLASS
。
CLASS
还有另一个用途:编译时仅使用的注释,例如 Proguard 的 @Keep
注释用于排除类、方法不被混淆。 - RobertBgetAnnotations
是错误的。例如:import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.CLASS)
@interface RetentionClass {}
@Retention(RetentionPolicy.RUNTIME)
@interface RetentionRuntime {}
public static void main(String[] args) {
@RetentionClass
class C {}
assert C.class.getAnnotations().length == 0;
@RetentionRuntime
class D {}
assert D.class.getAnnotations().length == 1;
}
因此,观察 RetentionPolicy.CLASS
注释的唯一方法是使用字节码解析器。
另一个区别在于,使用 Retention.CLASS
注释的类会获得一个 RuntimeInvisible 类属性,而使用 Retention.RUNTIME
注释则会获得一个 RuntimeVisible 类属性。可以使用 javap
进行观察。
在 GitHub 上的示例 供您参考。
默认情况下,注解不可通过反射 API 访问。 (RetentionPolicy.CLASS 是默认的保留策略)
您可以为自定义注解指定其是否应在运行时可用,以便通过反射进行检查。您可以通过使用 @Retention 注解对注解定义进行注释来实现此目的。
@Retention(RetentionPolicy.RUNTIME)
public @interface Version {
int test();
}
@Version(test= 1)
public class Engineer{
//code
}
public class Main {
public static void main(String[] args) {
Engineer engineer = new Engineer();
Annotation[] annotations = engineer.getClass().getAnnotations();
System.out.printf("%d annotations found.", annotations.length);
}
}
尝试通过将Version注释的RetentionPolicy更改为RetentionPolicy.CLASS再次运行代码并检查差异。
CLASS
。 - Adam Arold