从 JDK5 开始,Java增加对元数据的支持,也就是注解。简单理解就是代码里的特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。
注解可以被其他程序(比如:编译器等)读取,开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
注解就是以 @XXX 形式在代码中存在的,我们还可以为注解添加一些参数值,例如 @SuppressWarnings(value = "unchecked") 。
元注解就是负责注解其它注解的注解。
下图为Java定义的标准的 元注解类型,他们用来对其他的注解进行说明,可以在 Java API 的 java.lang.annotation 包中找到。
// since 1.5 @Documented @Retention(RUNTIME) @Target(ANNOTATION_TYPE) public @interface Documented
如果使用了 @Documented ,就说明此类(或方法、字段等)的文档化注释就会被包含在JavaDoc中。
// since 1.5 @Documented @Retention(RUNTIME) @Target(ANNOTATION_TYPE) public @interface Inherited
子类可以继承父类(超类)中的该注解。这个注解指定被他修饰的注解将具有继承性——如果某个类使用了@XXX,则其子类将自动被@XXX修饰
1 public class test2 { 2 3 public static void main(String[] args) { 4 Person person = new Person(); 5 Student student = new Student(); 6 7 Annotation[] parentAnnotation = person.getClass().getAnnotations(); 8 Annotation[] studentAnnotation = student.getClass().getAnnotations(); 9 for (Annotation annotation : parentAnnotation) { 10 System.out.println(annotation); 11 } 12 System.out.println("---------------------"); 13 for (Annotation annotation : studentAnnotation) { 14 System.out.println(annotation); 15 } 16 17 // 输出结果 18 // @com.ruiyicloud.bbfbusiness.demo.annotation.MyAnnotation3() 19 // --------------------- 20 // @com.ruiyicloud.bbfbusiness.demo.annotation.MyAnnotation3() 21 22 } 23 24 25 } 26 27 @Target({ElementType.TYPE}) 28 @Retention(RetentionPolicy.RUNTIME) 29 @Inherited 30 @interface MyAnnotation3{ 31 32 } 33 @MyAnnotation3 34 class Person{ 35 String name; 36 } 37 38 class Student extends Person{ 39 int age; 40 }
如果 MyAnnotation3 注解 去掉 @Inherited,则student.getClass().getAnnotations() 将输入空。
// since 1.8 @Documented @Target(FIELD) @Retention(SOURCE) public @interface Native
指示定义常量值的字段可以从本机代码引用。生成本机头文件的工具可以使用该注释作为提示,以确定是否需要头文件,如果需要,还应该包含哪些声明。
使用本地方法,我们可以用java与底层系统的交互,如果使用Java获取不到我们想要的内容,我们可以选择使用本地方法。
使用 @Native 注解修饰变量值的字段,则表示这个变量可以被本地代码引用。
附上Integer的部分源码
1 public final class Integer extends Number 2 implements Comparable<Integer>, Constable, ConstantDesc { 3 /** 4 * A constant holding the minimum value an {@code int} can 5 * have, -2<sup>31</sup>. 6 */ 7 @Native public static final int MIN_VALUE = 0x80000000; 8 9 10 11 // 比较值的大小 12 public static int compareUnsigned(int x, int y) { 13 return compare(x + MIN_VALUE, y + MIN_VALUE); 14 }
// since 1.8 @Documented @Retention(RUNTIME) @Target(ANNOTATION_TYPE) public @interface Repeatable
注释类型java.lang.annotation注释.Repeatable用于指示它(meta-)注释其声明的注释类型是可重复的。@Repeatable的值表示可重复注释类型的包含注释类型。
使用@Repeatable这个声明的注解是可重复的。@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。
FooContainer 作用于范围只能在注解类型上,所以作用于接口上时会报错
1 import java.lang.annotation.ElementType; 2 import java.lang.annotation.Repeatable; 3 import java.lang.annotation.Target; 4 5 public class test03 { 6 7 } 8 9 10 @Target({ElementType.TYPE,ElementType.ANNOTATION_TYPE}) 11 @Repeatable(FooContainer.class) 12 @interface Foo {} 13 14 @Target(ElementType.ANNOTATION_TYPE) 15 @interface FooContainer { 16 Foo[] value(); 17 } 18 19 //正确的 20 @Foo @Foo 21 @interface FooContainer1 { 22 Foo[] value(); 23 } 24 25 // 错误的 26 @Foo @Foo 27 interface aa { 28 29 }
// since 1.5 @Documented @Retention(RUNTIME) @Target(ANNOTATION_TYPE) public @interface Retention
枚举常量 | 描述 |
---|---|
CLASS |
枚举常量将由编译器记录在类文件中,但不需要在运行时由VM保留.
|
RUNTIME |
注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射地读取它们.
|
SOURCE |
注释将被编译器丢弃.
|
此注解主要作用为在什么级别保存该注解信息,用于描述注解的声明周期,需要主要的是 SOURCE < CLASS < RUNTIME 。
// since 1.5 @Documented @Retention(RUNTIME) @Target(ANNOTATION_TYPE) public @interface Target
@Target注解主要用于描述注解的使用范围(例如,添加某些属性的时候注解可以使用在类上,添加某些属性的时候注解可以使用在方法上等)
ElementType枚举常量 |
作用范围 |
TYPE | 类、接口(包括注释类型)、枚举或记录 |
FIELD | 字段声明(包括枚举常量) |
METHOD | 方法声明 |
PARAMETER | 形式参数声明 |
CONSTRUCTOR | 构造函数声明 |
LOCAL_VARIABLE | 局部变量声明 |
ANNOTATION_TYPE | 注解类型声明 |
PACKAGE | 包声明 |
TYPE_PARAMETER | 类型参数声明(since 8) |
TYPE_USE | 类型的使用(since 8) |
MODULE | 模块声明 (since 9) |
RECORD_COMPONENT | Java语言的一种预览功能(since 14) |
限定父类重写方法,当子类重写父类方法时,子类可以加上这个注解,可以确保子类确实重写了父类的方法,避免出现低级错误。
函数式接口,注解保证这个接口只有一个抽象方法,注意这个只能修饰接口。(函数式接口是指 接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。接口里面不能有私有的方法或变量。)
标示已过时,这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告。
抑制编译器警告,被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告。
本例创建一个简单的注解,并在方法上、类上进行使用
@MyAnnotation public class Main { @MyAnnotation public static void main(String[] args) { } } // Target 标识注解可以在什么地方使用 @Target({ElementType.METHOD,ElementType.TYPE}) // 标识此注解在什么地方还有效 @Retention(RetentionPolicy.RUNTIME) // 标识是否将我们的注解生成在JavaDoc中 @Documented // 子类可以继承父类的注解 @Inherited @interface MyAnnotation{ }
总的来说,注解还是比较简单的。