目录
1.基本注解
2.元注解
3.自定义注解
4.底层实现
1.基本注解
基本注解是JDK自带的一些单独使用的具有功能性的注解,包含以下四个:
@Override | 表示方法重写 |
@Deprecated | 表示方法过期,下个版本可能删除 |
@SuppressWarnings | 用于抑制告警 |
@SafeVarargs | JDK1.7后加入,当使用可变参数,而参数的类型又是泛型的话就会出现告警,使用该注解可以去掉告警 |
@SuppressWanings支持一些参数:
deprecation | 使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告) |
unchecked | 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告 |
fallthrough | 当 switch 程序块直接通往下一种情况而没有 Break 时的警告 |
path | 在类路径、源文件路径等中有不存在的路径时的警告 |
serial | 当在可序列化的类上缺少 serialVersionUID 定义时的警告 |
finally | 任何 finally 子句不能正常完成时的警告 |
rawtypes | 泛型类型未指明 |
unused | 引用定义了,但是没有被使用 |
all | 关于以上所有情况的警告 |
使用示例:
@SuppressWanings({ "rawtypes", "unused" })
2.元注解
元注解是专门留给开发者自定义注解使用的,也就是可以用在注解中的注解。
@Target | 表示这个注解允许被放在什么位置 |
@Retention | 用来声明生效的生命周期 |
@Inherited | 表示注解可以被子类继承,即子类继承父类后,也可以继承父类的注解。 |
@Documented | 表示生成API |
@Repeatable | 表示注解在同一个地方可以出现多次,如果不加这个注解的话,同一个地方注解只能出现一次。 |
@Target支持多种枚举类型的参数:
ElementType.TYPE | 能修饰类、接口或枚举类型 |
ElementType.FIELD | 能修饰成员变量 |
ElementType.METHOD | 能修饰方法 |
ElementType.PARAMETER | 能修饰参数 |
ElementType.CONSTRUCTOR | 能修饰构造器 |
ElementType.LOCAL_VARIABLE | 能修饰局部变量 |
ElementType.ANNOTATION_TYPE | 能修饰注解 |
ElementType.PACKAGE | 能修饰包 |
@Retention支持多种枚举类型的参数:
RetentionPolicy.SOURCE | 源码阶 |
RetentionPolicy.CLASS | 编译阶段 |
RetentionPolicy.RUNTIME | 运行阶段 |
3.自定义注解
无参:
@Target(ElementType.TYPE)
public @interface Test {
}
单参:
@Target(ElementType.TYPE)
public @interface SingleTest {
int value() default 0;
}
多参:
@Target(ElementType.TYPE)
public @interface MultipleTest {
int a() default 0;
int b() default 0;
}
使用:
@Test
@SingleTest(value=1)
@MultipleTest(a=1,b=2)
public class Main {
}
4.底层实现
总过程:
- 注解采用接口种的方法来表示变量
- Java为注解产生一个代理类,这个代理类包括一个AnnotationInvocationHandler成员变量,用来存储所有的注解的属性赋值。
- 在程序中,调用注解接口的方法,将会被代理类接管,然后根据方法名字,到Map里面拿相应的Value并返回。
详细过程:
每个注解被编译以后都是一个接口,如果用接口里面的成员变量来存值,那么直接就是一个常量了,没办法动态修改,所以将变量以方法的形式存储。
JAVA会为每个注解生成代理对象,JAVA中的代理对象都会继承Proxy,Proxy中持有一个invocationHandler的成员变量,所以构造函数被调用的时候,会被传入一个invocationhandler,这个invocationhandler也是由JDK生成传入的。
这个invocationhandler中持有一个Map,K—方法名,V—变量的值。实际调用注解的值的时候,调用的是父类Proxy所持有的那个invocationHandler的invoke方法。