一、注解概述
Annotation其实就是代码里的特殊标记们这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署;
Annotation可以像修饰符一样被使用,可用于修饰类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中;
二、常见的Annotation示例
2.1、生成帮助文档的注解
2.2、在编译时进行格式检查(JDK内置的三个基本注解)
- @Override:限制重写父类方法,该注解只能用于方法
- @Deprecated:用于表示所修饰的元素(类,方法等)已过时。通常时因为所修饰的结构危险或存在更好的选择
- @SupperssWarnings:抑制编译器警告
2.3、跟踪代码依赖性,实现替代配置文件功能
三、自定义注解
- 自定义新的Annotation类型使用@interface关键字
- 自定义注解自动继承了java.lang.annotation.Annotation接口
- Annotation的成员变量在Annotation定义中yi无参数方法的形式来声明。其中方法名和返回值定义了该成员的名字和类型。我们称为配置参数。类型只能时八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、以上所有类型的数组
- 可以在定义Annotaion的成员变量时为其指定初始值,指定成员变量的初始值可以使用default关键字
- 如果只有一个参数成员,建议使用参数名为value
- 如果定义注解含有配置参数,那么使用时必须指定参数值,除非它有默认值。格式是"参数名=参数值",如果只有一个成员参数,且名称为value,可以省略"value="
- 没有成员定义的Annotation称为标记,包含成员变量的Annotation称为元数组Annotation
public @interface MyAnnotation {
String value() default "Sakura";
}
@MyAnnotation("Mikoto")
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
四、JDK中的元注解
JDK的元注解用于修饰其它Annotation,JDK 5.0 提供了4个标准的meta-annotation,分别是
- Retention:用于指定该Annotation的声明周期,@Retention包含一个RetentionPolicy类型的变量,使用@Retention时必须为该value成员变量指定值:
- RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释
- RetentionPolicy.CLASS:在class文件中有效(即class保留),当运行Java程序时,JVM不会保留注解。这是默认值
- RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行Java程序时,JVM会保留注释。程序可以通过反射获取该注解
- Target:用于指定被修饰Annotation能用于修饰哪些程序元素,@Target包含一个名为value的成员变量
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部变量
- METHID:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型)或enum声明
- Documented:用于指定被修饰的Annotation类将被javadoc工具提取成文档。默认情况下,javadoc是不包含注解的
- 定义为Documented的注解必须设置Retention值为RUNTIME
- Inherited:被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解
五、JDK 8 中注解的新特性
5.1、可重复注解
5.1.1、JDK 8.0 之前
public @interface MyAnnotations {
MyAnnotation[] value();
}
public @interface MyAnnotation {
String value() default "Sakura";
}
@MyAnnotations({@MyAnnotation("Kagome"),@MyAnnotation("Kikyo")})
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
5.1.1、JDK 8.0 之后
- 在自定义注解MyAnnotation上声明@Repeatable,成员值为MyAnnotation.class
- MyAnnotation的Target和Retention、Target、Inherited等元注解与MyAnnotations相同
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
public @interface MyAnnotations {
MyAnnotation[] value();
}
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Inherited
@Repeatable(MyAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
public @interface MyAnnotation {
String value() default "Sakura";
}
@MyAnnotation("Kagome")
@MyAnnotation("Kikyo")
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人走路");
}
public void eat(){
System.out.println("人吃饭");
}
}
5.2、类型注解
- ElementType.TYPE_PARAMETER:表示该注解能写在类型变量的声明语句中
- ElementType.TYPE_USE:表示该注解能写在使用类型的任何语句中
import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Target;
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
public @interface MyAnnotation {
String value() default "Sakura";
}
import java.util.ArrayList;
public class Generic<@MyAnnotation T> {
public void show() throws @MyAnnotation RuntimeException{
ArrayList<@MyAnnotation String> list = new ArrayList<>();
int num = (@MyAnnotation int)10L;
}
}