一、什么是注解

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。注解是ava5开始引入的新特征。

二、常见的Java注解

  1. Override
    java.lang.Override 是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重写了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java 编译器将以一个编译错误来警示。
  1. Deprecated
    Deprecated 也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated 修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。
  1. SuppressWarnings
    SuppressWarning 不是一个标记类型注解。它有一个类型为String[] 的成员,这个成员的值为被禁止的警告名。

三、注解的语法

  1. 注解定义
    注解通过@Interface关键字进行定义:
    1
    2
    public @interface TestAnnocation {
    }
  2. 注解使用
    注解可以应用到类、方法、成员变量上:
    1
    2
    3
    @TestAnnocation
    public class Test {
    }

四、元注解

元注解是作用于注解的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。元注解有:@Retention@Documented@Target@Inherited@Repeatable 5 种。

1.@Retention 定义该注解的生命周期
● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

2.@Documented是个标记性注解,表示是否将注解信息添加在java 文档中

3.@Target表示该注解用于什么地方,默认值为任何元素
● ElementType.CONSTRUCTOR: 用于描述构造器
● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
● ElementType.LOCAL_VARIABLE: 用于描述局部变量
● ElementType.METHOD: 用于描述方法
● ElementType.PACKAGE: 用于描述包
● ElementType.PARAMETER: 用于描述参数
● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明

4.@Inherited是个标记性注解,定义该注解和子类的关系
@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited 修饰的annotation 类型被用于一个class,则这个annotation 将被用于该class 的子类。

5.@Repeatable

五、注解的属性

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

1
2
3
4
5
6
7
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestAnnocation {

int id();
String msg();
}

在使用的时候,我们应该给它们进行赋值。赋值的方式是在注解的括号内以 value=”” 形式,多个属性之前用 ,隔开。

1
2
3
@TestAnnocation(id = 1, msg = "hello")
public class Test {
}

使用default关键字可以为属性指定默认值。

1
2
3
4
5
6
7
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestAnnocation {

int id() default 1;
String msg() default "hello";
}

六、自定义注解

自定义注解类编写的一些规则:

  1. Annotation 型定义为@interface, 所有的Annotation 会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.
  2. 参数成员只能用public 或默认(default) 这两个访问权修饰
  3. 参数成员只能用基本类型byte、short、char、int、long、float、double、boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.
  4. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的方法
  5. 注解也可以没有定义成员,,不过这样注解就没啥用了
    PS:自定义注解需要使用到元注解

七、注解原理

注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandlerinvoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。