前言
在文章开始之前,你是否知道如何解答下列问题?
- 注解是什么?
- 注解有什么意义?
- 如何声明一个注解类型?
- 元注解是什么?
- 元注解
@Target、@Retention分别如何使用? - 对于注解类型元素你都知道什么?
- 注解在不同保留级别下的应用场景有哪些?
下文将给出详细说明。
1. 注解概述
1.1 注解是什么?
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。
元数据:描述数据的数据。
1.2 注解的作用或意义是什么?
单独的注解就就是一种注释,就如同超市中的标签一样。注解本身没有任何代码意义。
注解结合其他技术使用才有意义,比如反射、插桩等。
2. 注解声明
2.1 声明一个注解类型
注解的声明使用@interface关键字:
public @interface Liang {
}
Java 中所有注解默认实现Annotation接口:
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
2.2 元注解
在定义注解时,注解类也能够使用其他的注解声明。对注解类型进行注解的注解类,我们称之为 meta-annotation(元注解)。
元注解是注解的注解。
@Target
@Target:目标注解,标记另一个注解,以限制可以应用注解的 Java 元素类型,即指定注解可以写到什么地方。目标注解指定以下元素类型之一作为其值:
ElementType.ANNOTATION_TYPE:可以应用于注解类型。ElementType.CONSTRUCTOR:可以应用于构造函数。ElementType.FIELD: 可以应用于字段或属性。ElementType.LOCAL_VARIABLE: 可以应用于局部变量。ElementType.METHOD: 可以应用于方法级注解。ElementType.PACKAGE: 可以应用于包声明。ElementType.PARAMETER: 可以应用于方法的参数。ElementType.TYPE: 可以应用于类。
//@Target(ElementType.TYPE) //元注解,Target作用在Liang上,此处指定Liang只能作用在类上面。
@Target({ElementType.TYPE,ElementType.FIELD}) // 可以同时指定多个地方,用在允许在类与类属性上标记该注解
@Retention(RetentionPolicy.SOURCE) //注解保留在源码中
public @interface Liang {
}
@Retention
@Retention:指定标记注解的存储方式,保留级别,注解的生命周期,注解可以存活到什么时候:
RetentionPolicy.SOURCE: 标记的注解仅保留在源码级别中,并被编译器忽略。RetentionPolicy.CLASS: 标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略。RetentionPolicy.RUNTIME: 标记的注解由 JVM 保留,因此运行时环境可以使用它。
注:可以在字节码中查看。
2.3 注解类型元素
在使用注解时,允许传递参数,可以定义可选的默认值。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Liang {
String value(); // String 类型的 value 元素
String apple() default "a"; // 有默认值
}
// 注解的使用
@Liang(value = "1", apple = "11")
public class MyClass {
...
}
注:注解里面有元素,default 后可以设置默认值,设置默认值时,使用注释可以不传参,没有默认值时,必须传参。
这里注意,value 元素较特殊,若注解中仅有 value 一个元素时,传参时可以不用声明。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Liang {
String value();
}
//注解的使用,声明首字母
@Liang("11")
public class MyClass {}
若改成其他元素,使用时需声明。注解中有多个元素时,即使是 value 元素,也需要声明。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Liang {
String value();
String string();
}
@Liang(value = "1", s = "11")
3. 注解的应用场景
根据注解的保留级别不同,对应的使用场景也不同:由注解的三个不同保留级别可知,注解作用于:SOURCE(源码)、CLASS(字节码)与RUNTIME(运行时)。
| 级别 | 技术 | 说明 |
|---|---|---|
| 源码 | APT注解处理器/IDE语法检查 | 在编译期能够获取注解与注解声明的类包括类中的所有的成员信息,一般用于生成额外的辅助类 |
| 字节码 | 字节码增强 | 在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。 |
| 运行时 | 反射 | 在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。 |
对于不同的保留级别,注解有不同的应用:
-
RetentionPolicy.SOURCE:- APT 注解处理器
- IDE 语法检查:注解实现自定义IDE语法检查规则替代枚举常量
-
RetentionPolicy.CLASS:- 字节码增强:在字节码中写代码
-
RetentionPolicy.RUNTIME:- 反射
注解在不同应用场景的具体使用待补充...