一、引言
java注解是从jdk5引入的,jave中的注解分文 内置注解 自定义注解 ,而内置注解包括了普通的注解和元注解,元注解就是用来定义注解的注解,java底层注解的实现是反射机制来实现的。
什么是注解?
注解是源代码的元数据,可以理解为代码的标签。
可以简化配置;
增加代码的可读性;
提高系统的可维护性;
二、内置注解
1、普通注解
- @Override:用于标识该方法继承自超类, 当父类的方法被删除或修改了,编译器会提示错误信息;
- @Deprecated:表示该类或者该方法已经不推荐使用,已经过期了,如果用户还是要使用,会生成编译的警告;
- @SuppressWarnings:用于忽略的编译器警告信息;
- @Test:Junit测试;
- @SafeVarargs:专门为抑制“堆污染”警告提供的;
2、元注解
-
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效);
RetentionPoicy 有三个值: 1.SOURCE:在源文件中有效(即源文件保留) 2.CLASS:在class文件中有效(即class保留) 3.RUNTIME:在运行时有效(即运行时保留)
-
@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
ElementType 取值范围: 1.CONSTRUCTOR:用于描述构造器 2.FIELD:用于描述域 3.LOCAL_VARIABLE:用于描述局部变量 4.METHOD:用于描述方法 5.PACKAGE:用于描述包 6.PARAMETER:用于描述参数 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
-
@Document:说明该注解将被包含在javadoc中,是一个标记性注解;
-
@Inherited:阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类,是一个标记性注解;
三、自定义注解
1、@interface
public @interface 注解名 {定义体}
-
注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short) 2.String类型 3.Class类型 4.enum类型 5.Annotation类型 6.以上所有类型的数组
-
Annotation类型里面的参数该怎么设定:
1.只能用public或默认(default)这两个访问权修饰 2.如果只有一个参数成员,最好把参数名称设为"value",后加小括号 3.注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null
2、代码练习
1. 自定义一个注解类 AnnotationDemo.class
package zidingyizhujie.annotation;
import enums.KeyCodesEnums;
import java.lang.annotation.*;
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
// key值 是个枚举类
KeyCodesEnums key();
// 名称
String name();
// 数据值
String value() default "default";
}
枚举类:KeyCodesEnums.class
package enums; public enum KeyCodesEnums { MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日"); private String text; KeyCodesEnums(String text) { this.text = text; } public String getText() { return text; } public void setText(String text) { this.text = text; } }
2. 定义一个使用该注解的类
package zidingyizhujie;
import enums.KeyCodesEnums;
import lombok.extern.slf4j.Slf4j;
import zidingyizhujie.annotation.AnnotationDemo;
/**
* @project: java_syudy_moduls
* @author: 13965
* @date:2021/3/5 10:24
* @description:
*/
@Slf4j
@AnnotationDemo(key = KeyCodesEnums.FRIDAY, name = "testClass")
public class AnnotationUseDemo {
@AnnotationDemo(key = KeyCodesEnums.MONDAY, name = "testMethod")
public void useAnnotationMethod() {
}
}
四、自定义注解的解析
注解它本身是没什么用的,只有在恰当的时候,由外部程序解析才会产生作用
使用jdk反射去获取注解信息
Java通过反射机制解析注解,java在java.lang.reflect包下新增了AnnotatedElement接口, AnnotatedElement是所有注解元素的父接口,所有的注解元素都可以通过某个类反射获取AnnotatedElement对象,该对象有一下4个方法来访问Annotation信息。
(1)<T extends Annotation> T getAnnotation(Class<T> annotationClass)
返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
(2)Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
(3)boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)
判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
(4)Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
单元测试类 AnnotationTestDemo.class
package zidingyizhujie;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import zidingyizhujie.annotation.AnnotationDemo;
import java.lang.reflect.Method;
/**
* @project: java_syudy_moduls
* @author: 13965
* @date:2021/3/5 15:18
* @description:
*/
@Slf4j
public class AnnotationTestDemo {
// 通过反射机制,解析自定义的注解 类
@Test
public void annotationClassResoveTest() {
// 使用注解的类的反射对象
Class<AnnotationUseDemo> annotationUseDemoClass = AnnotationUseDemo.class;
// 自定义注解类的反射对象
Class<AnnotationDemo> annotationDemoClass = AnnotationDemo.class;
if (annotationUseDemoClass.isAnnotationPresent(annotationDemoClass)) {
AnnotationDemo annotationDemo = annotationUseDemoClass.getAnnotation(annotationDemoClass);
log.info("注解的参数>>>>>>name:" + annotationDemo.name());
log.info("注解的参数>>>>>>value:" + annotationDemo.value());
log.info("注解的参数>>>>>>key:" + annotationDemo.key());
}
}
// 通过反射机制,解析自定义的注解 方法
@Test
public void annotationMethodResoveTest() {
// 使用注解的类的反射对象
Class<AnnotationUseDemo> annotationUseDemoClass = AnnotationUseDemo.class;
// 自定义注解类的反射对象
Class<AnnotationDemo> annotationDemoClass = AnnotationDemo.class;
Method[] methods = annotationUseDemoClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(annotationDemoClass)) {
AnnotationDemo annotationDemo = annotationUseDemoClass.getAnnotation(annotationDemoClass);
log.info("注解的参数>>>>>>name:" + annotationDemo.name());
log.info("注解的参数>>>>>>value:" + annotationDemo.value());
log.info("注解的参数>>>>>>key:" + annotationDemo.key());
}
}
}
}
运行结果:因为我们在 AnnotationUseDemo 类中,类和方法均使用了注解 @AnnotationDemo ,这里的单元测试解析注解,获得结果为:
15:50:01.551 [main] INFO zidingyizhujie.AnnotationTestDemo - 注解的参数>>>>>>name:testClass 15:50:01.557 [main] INFO zidingyizhujie.AnnotationTestDemo - 注解的参数>>>>>>value:default 15:50:01.557 [main] INFO zidingyizhujie.AnnotationTestDemo - 注解的参数>>>>>>key:FRIDAY 15:50:01.559 [main] INFO zidingyizhujie.AnnotationTestDemo - 注解的参数>>>>>>name:testClass 15:50:01.560 [main] INFO zidingyizhujie.AnnotationTestDemo - 注解的参数>>>>>>value:default 15:50:01.560 [main] INFO zidingyizhujie.AnnotationTestDemo - 注解的参数>>>>>>key:FRIDAY