注解
- 就是Java代码里的特殊标记,比如:@Override、@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序
- 注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处
自定义注解
就是自己定义注解
自定义注解到底该怎么写:
public @interface MyTest1 {
String aaa();
boolean bbb() default true;
String[] ccc();
}
自定义注解写了属性,在使用注解时,除非该属性设置了默认值,不然一定要给属性赋值
特殊属性名:value
- 如果注解中只有一个value属性,使用注解时,value名称可以不写!!
public @interface MyTest2 {
String value(); //特殊属性
}
注解可以用在类、方法、变量等:
package com.zeyu.annotation;
@MyTest1(aaa="zeYu",ccc={"aaa","bbb","ccc"})
//@MyTest2(value="zeYu")
@MyTest2("zeYu") //注解中只有一个value属性,使用注解时,value名称可以不写
public class annotationTest1 {
@MyTest1(aaa="zeYu",bbb=false,ccc={"ddd","eee"})
public void test1(){
}
}
注解的原理
- 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的
- @注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口
元注解
- 指的是:修饰注解的注解
例如:
常用元注解:
代码演示:
package com.zeyu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.METHOD}) //ElementType.TYPE表示该注解只可以用在类和方法上
@Retention(RetentionPolicy.RUNTIME) //控制下面的注解一直保留到运行时
public @interface MyTest3 {
}
测试:
package com.zeyu.annotation;
@MyTest3 //用在类上没问题
public class annotationTest2 {
// @MyTest3 //用在成员变量不行
public String name;
@MyTest3 //用在方法上没问题
public void test(){
}
}
什么是注解的解析?
就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来
如何解析注解?
- 指导思想:要解析谁上面的注解,就应该先拿到谁
- 比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解
- 比如要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解
- Class、Method、Field、Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力
解析注解的案例
具体需求如下:
- 定义注解MyTest4,要求如下
包含属性:String value()
包含属性:double aaa(),默认值为 100
包含属性:Stringll bbb()
限制注解使用的位置:类和成员方法上
指定注解的有效范围:一直到运行时 - 定义一个类叫:Demo,在类中定义一个test1方法,并在该类和其方法上使用MyTest4注解
- 定义AnnotationTest3测试类,解析Demo类中的全部注解
代码:
MyTest4:
package com.zeyu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
String value();
double aaa() default 100;
String[] bbb();
}
Demo:
package com.zeyu.annotation;
@MyTest4(value="zeYu",bbb={"aaa","bbb"})
public class Demo {
@MyTest4(value="zeYu",bbb={"ccc","ddd"})
public void test1(){
}
}
annotationTest3:
package com.zeyu.annotation;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
public class annotationTest3 {
@Test
public void parseClass(){
//先得到Class对象
Class c = Demo.class;
//判断类上是否包含了某个注解
if(c.isAnnotationPresent(MyTest4.class)){
MyTest4 myTest4 = (MyTest4) c.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 Exception {
//先得到Class对象
Class c = Demo.class;
Method test1 = c.getDeclaredMethod("test1");
//判断类上是否包含了某个注解
if(test1.isAnnotationPresent(MyTest4.class)){
MyTest4 myTest4 = (MyTest4) test1.getDeclaredAnnotation(MyTest4.class);
System.out.println(myTest4.value());
System.out.println(myTest4.aaa());
System.out.println(Arrays.toString(myTest4.bbb()));
}
}
}
测试结果:
案例:模拟Junit框架
需求
- 定义若干个方法,只要加了MyTest注解,就会触发该方法执行
分析
- 定义一个自定义注解MyTest,只能注解方法,存活范围是一直都在
- 定义若干个方法,部分方法加上@MyTest注解修饰,部分方法不加
- 模拟一个junit程序,可以触发加了@MyTest注解的方法执行
代码:
MyTest:
package com.zeyu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) //只能用在方法上
@Retention(RetentionPolicy.RUNTIME) //一直到运行时都存在
public @interface MyTest {
}
测试类:
package com.zeyu.annotation;
import java.lang.reflect.Method;
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 Exception {
//1、得到Class对象
Class c = annotationTest4.class;
annotationTest4 a = new annotationTest4();
//2、提取这个类中的全部成员方法
Method[] methods = c.getDeclaredMethods();
//3、遍历这个数组中的每个方法,看方法上是否存在@MyTest注解,存在则执行该方法
for (Method method : methods) {
if (method.isAnnotationPresent(MyTest.class)) {
//说明存在该注解,执行该方法
method.invoke(a);
}
}
}
}
运行结果: