目录
1.Java注解的定义
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到 说明、配置的功能
--注解相关类都包含在java.lang.annotation包中
2.Java注解的分类
三大注解:JDK基本注解、JDK元注解、JDK自定义注解
2.1.JDK基本注解
@Override 重写
@Deprecated:已过时
@SuppressWarnings(value = "unchecked") :压制编辑器警告
2.2.JDK元注解
元注解用于修饰其他的注解(如纪委:管干部的干部),简单来说元注解就是管理注解的注解
--2.2.1 @Retention:定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到
--2.2.2 @Target:指定被修饰的Annotation可以放置的位置(被修饰的目标)
@Target(ElementType.TYPE) //接口、类
@Target(ElementType.FIELD) //属性
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE) //局部变量
@Target(ElementType.ANNOTATION_TYPE) //注解
@Target(ElementType.PACKAGE) //包
注:可以指定多个位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上 面使用
--2.2.3 @Inherited:指定被修饰的Annotation将具有继承性
--2.2.4 @Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档
补充:根据Annotation是否包含成员变量,可以把Annotation分为两类: ①标记Annotation:
没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息
②元数据Annotation:
包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据
2.3.JDK自定义注解
使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:
Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值 类型定义了该成员变量的名字和类型, 而且我们还可以使用default关键字为这个成员变量设定 默认值
枚举(enum):使用枚举,就能把范围规定到“Read, Write, ReadWrite”当中,这样就可以避免范围外的数值
package com.zking.test.p1; //枚举类 public enum TranscationModel { Read, Write, ReadWrite }
MyAnnotation1.java:
package com.zking.test.p1; import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnnotation1 { String name(); // String value(); }
MyAnnotation2.java:
package com.zking.test.p1; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnnotation2 { TranscationModel model() default TranscationModel.ReadWrite; }
MyAnnotation3.java:
package com.zking.test.p1; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) @Documented public @interface MyAnnotation3 { TranscationModel[] models() default TranscationModel.ReadWrite; }
Demo1:在该类中使用以上3个自定义注解来标识类和字段
package com.zking.test.p1; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @MyAnnotation1(name = "abc") public class Demo1 { @MyAnnotation1(name = "xyz") private Integer age; @MyAnnotation2(model = TranscationModel.Read) public void list() { System.out.println("list"); } @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write}) @RequestMapping("/edit") @ResponseBody public void edit() { System.out.println("edit"); } }
3.如何提取Annotation信息
使用AnnotatedElement接口中的方法提取注解中的数据,像Class/Constructor/Field/Method/Package这些类都实现了AnnotatedElement接口。
注:只有当定义Annotation时使用了@Retention(RetentionPolicy.RUNTIME)修饰,JVM才会在装载class文件时提取保存在class文件中的Annotation,该Annotation才会在运行时可见,这样我们才能够解析
Demo1Test:通过以上的Demo1来提取Annotation信息
package com.zking.test; import com.zking.test.p1.*; import org.junit.Before; import org.junit.Test; import java.lang.reflect.Method; import java.util.Arrays; public class Demo1Test { @Before public void setUp() throws Exception { } @Test public void test1() throws Exception { MyAnnotation1 annotation = Demo1.class.getAnnotation(MyAnnotation1.class); System.out.println(annotation.name()); //annotation = Demo1.class.getDeclaredField("age").getAnnotation(MyAnnotation1.class); //System.out.println(annotation.name()); } @Test public void test2() throws Exception { Method method = Demo1.class.getMethod("list"); System.out.println(method); MyAnnotation2 annotation2 = method.getAnnotation(MyAnnotation2.class); TranscationModel model = annotation2.model(); System.out.println(model); } @Test public void test3() throws Exception { Method method = Demo1.class.getMethod("edit"); System.out.println(method); MyAnnotation3 annotation3 = method.getAnnotation(MyAnnotation3.class); TranscationModel[] models = annotation3.models(); System.out.println(Arrays.toString(models)); } }
test1():结果为abc
test2():先拿到 list 这个方法,再去提取该方法的Annotation信息,结果为Read
test3():先拿到 edit 这个方法,再去提取该方法的Annotation信息,你会发现以下类似的空指针问题的报错,是因为@Retention(RetentionPolicy.CLASS) 保留策略,注解会在class字节码文件中存在,但运行时无法获得
4.注解处理器
4.1 为什么需要注解处理器
使用Annotation修饰了类/方法/成员变量等之后,这些Annotation不会自己生效,为了让程序中的这些注解起作用, 必须由这些注解的开发者为这些注解提供一个注解处理器(Annotation Processor)。另外,在编译期间,JVM会自动运行注解处理器(当然,我们需要将其注册)
4.2 如何实现一个注解处理器
--4.2.1 定义注解
--4.2.2 编写注解处理器
--4.2.3 注册注解处理器
详细的实现过程可参考:https://blog.csdn.net/top_code/article/details/53968145
以上是我的学习记录,第一次写,略显生疏,若有错误,欢迎指正!