※ 学习目标
- 什么是注解?
- 注解的作用是啥?
- 如何自定义注解?
- 元注解是什么?各自的作用是什么?
- 什么是注解的解析?注解解析的步骤是啥?
一、什么是注解
就是Java代码里的特殊标记,比如:@Override,@Test等
作用是:让其他程序根据注解信息来解决怎么执行该程序。
注意:注解可以用在类、构造器、方法、成员变量、参数等位置
二、自定义注解
自定义注解的格式
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
}
特殊属性名:value
如果注解中只有一个value属性,使用注解时,value名称可以不写!
三、注解原理
- 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的。
- @注解(…):其实就是一个实现类对象,实现了改注解以及Annotation接口
四、元注解
修饰注解的注解
4.1 @Target
作用:声明被修饰的注解只能在哪些位置使用
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyTest3 {
}
4.2 @Retention
作用:声明注解的保留周期
// 一般使用 RetentionPolicy.RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest3 {
}
五、注解的解析
判断类、方法、成员变量上是否存在注解,并把注解的内容解析出来
如何解析注解?
- 指导思想:要解析谁上面的注解,就应该先拿到谁。
- 要解析类上面的注解,应该先获取该类的Class对象,再通过Class对象解析其上面的注解
- 要解析成员方法上的注解,应该先获取成员方法的Method对象,再通过Method对象解析上面的注解
- Class、Method、Field、Constructor,都实现了AnnotatedElement接口,都拥有解析注解的能力
API
方法 | 说明 |
---|---|
public Annotation[] getDeclaredAnnotations() | 获取当前对象上面的注解 |
public T getDeclaredAnnotation(Class annotationClass) | 获取指定的注解对象 |
public boolean isAnnotationPresent(Class annotationClass) | 判断当前对象上是否存在某个注解 |
/**
* 目标:掌握注解解析
* <p>
* 1. 定义注解 @MyTest4
* 属性:String value()
* double aaa() 默认值 100
* String[] bbb()
* 限制注解的位置:类和方法上
* 限制注解的有效范围:一直到运行时
* 2. 当以一个类:Demo,在类中定义一个test1方法,并在该类和其方法上使用 @MyTest4 注解
* 3. 定义 AnnotationTest3测试类,解析Demo类中的全部注解
*/
public class AnnotationTest3 {
@Test
public void parseClass() {
// 1. 得到Class对象
Class demoClass = Demo.class;
// 2. 获取当前对象的所有注解
Annotation[] annotations = demoClass.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
System.out.println("---------------------------------------------------");
// 4. 判断当前对象上是否存在某个注解
boolean present = demoClass.isAnnotationPresent(MyTest4.class);
if (present) {
// 3. 获取指定的注解对象
MyTest4 myTest4 = (MyTest4) demoClass.getDeclaredAnnotation(MyTest4.class);
System.out.println(myTest4.value());
System.out.println(myTest4.aaa());
System.out.println(Arrays.toString(myTest4.bbb()));
}
}
@Test
public void parseMethod() throws NoSuchMethodException {
// 1. 得到Class对象
Class demoClass = Demo.class;
// 2. 获取方法
Method method = demoClass.getDeclaredMethod("test1");
// 2. 获取当前对象的所有注解
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
System.out.println("---------------------------------------------------");
// 4. 判断当前对象上是否存在某个注解
boolean present = method.isAnnotationPresent(MyTest4.class);
if (present) {
// 3. 获取指定的注解对象
MyTest4 myTest4 = (MyTest4) method.getDeclaredAnnotation(MyTest4.class);
System.out.println(myTest4.value());
System.out.println(myTest4.aaa());
System.out.println(Arrays.toString(myTest4.bbb()));
}
}
}
@MyTest4(value = "蜘蛛精", aaa = 999.5, bbb = {"至尊宝", "牛魔王"})
public class Demo {
@MyTest4(value = "孙悟空", aaa = 1999.5, bbb = {"紫霞", "刘夫人"})
public void test1() {
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
String value();
double aaa() default 100;
String[] bbb();
}
六、应用场景
定义若干方法,只要加了 MyTest 注解,就会触发该方法的执行。
- 定义一个自定义注解 MyTest ,只能注解方法,存活范围是一直都在。
- 定义若干方法,部分方法加上 @MyTest 注解修饰,部分方法不加。
- 模拟一个junit程序,可以触发加了 @MyTest 注解的方法执行。
public class AnnotationTest4 {
@MyTest
public void test1() {
System.out.println("------------ test1 ------------");
}
// @MyTest
public void test2() {
System.out.println("------------ test2 ------------");
}
@MyTest
public void test3() {
System.out.println("------------ test3 ------------");
}
@MyTest
public void test4() {
System.out.println("------------ test4 ------------");
}
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
AnnotationTest4 annotationTest4 = new AnnotationTest4();
Class aClass = AnnotationTest4.class;
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(annotationTest4);
}
}
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}