Annotation知识积累
Annotation知识积累
1.Annotation注解的基础知识点
1.1定义:
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
- 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
- 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
- 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
需要注意的是java注解有4个元注解,用于作用在其他注解的注解
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
1.2三个重要的主干类
Annotation
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
ElementType
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
RetentionPolicy
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
说明:
(01) Annotation 就是个接口。
"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联,并且与 "1~n 个 ElementType" 关联。可以通俗的理解为:每 1 个 Annotation 对象,都会有唯一的 RetentionPolicy 属性;至于 ElementType 属性,则有 1~n 个。
(02) ElementType 是 Enum 枚举类型,它用来指定 Annotation 的类型。
"每 1 个 Annotation" 都与 "1~n 个 ElementType" 关联。当 Annotation 与某个 ElementType 关联时,就意味着:Annotation有了某种用途。例如,若一个 Annotation 对象是 METHOD 类型,则该 Annotation 只能用来修饰方法。
(03) RetentionPolicy 是 Enum 枚举类型,它用来指定 Annotation 的策略。通俗点说,就是不同 RetentionPolicy 类型的 Annotation 的作用域不同。
"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联。
a) 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override" 就没有任何作用了。
b) 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。
c) 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。
这时,只需要记住"每 1 个 Annotation" 都与 "1 个 RetentionPolicy" 关联,并且与 "1~n 个 ElementType" 关联。学完后面的内容之后,再回头看这些内容,会更容易理解。
2.常用的Annotation功能
(1)用于拦截器中对指定接口进行处理
例如:自定义注解+拦截器 实现登录校验
(2) 用于切面对指定方法进行处理
例如:自定义注解+AOP 实现日志输出
(3)用于实体类,可为该类,字段等添加注解,实现一些复杂功能
例如
1)Excel 数据导入导出
2)ES根据查询实体生成 query查询语向
3.写一个拥有基本功能的注解
3.1创建一个注解
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target(value = METHOD)//此注解用于修饰方法
@Retention(value = RUNTIME)//运行时起作用
public @interface initdata {
String msg() default "default annotation param -";//定义一个属性做演示
}
注意:两个必须设置的元注解,分别定义注解的使用对象和注解的使用范围。
3.2在自定义类中使用注解
public class Demo {
@initdata(msg = "user set annotation param")
public void init(String param){
System.out.println("this is method init 1 param :"+param);
}
@initdata
public void init2(String param){
System.out.println("this is method init 2 param :"+param);
}
}
方法1添加了属性值,而方法2中没有添加。
3.3使用反射的机制,添加对应的功能
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
Class clazz = Class.forName("Demo");
Method[] methods = clazz.getMethods();
if(methods!=null && methods.length != 0){
for(Method method : methods){
boolean flag = method.isAnnotationPresent(initdata.class);
if(flag){
//打印注解中的参数
initdata annotation = method.getAnnotation(initdata.class);
System.out.println((annotation.msg()));
//实例化对象
Demo demo = (Demo)clazz.getConstructor(null).newInstance(null);
//调用此方法
method.invoke(demo,"param - 在反射中调用");
}
}
}
}
}
3.4输出结果:
user set annotation param
this is method init 1 param :param - 在反射中调用
default annotation param -
this is method init 2 param :param - 在反射中调用
4.总结
注解仅仅是元数据,不包括任何业务逻辑。一个注解应该有对应的消费者,否则定义的注解是没有任何作用的。也就是需要在合适的时机来翻译注解对应的逻辑,一般可以结合反射技术来实现。比如@Override这个注解它在字节码级别工作 本身没有任何业务逻辑,JVM是它的消费者负责把相应的逻辑解析出来。