注解
概述,自定义注解
注解(Annotation)
- 就是java代码里的特殊标记,比如@Override,@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序.
- 注意: 注解可以用在类上,构造器上,方法上,成员变量上,参数上,等位置处.
自定义注解
1 2 3
| public @interface 注解名称 { public 属性类型 属性名() default 默认值; }
|
使用:
1 2 3 4 5 6 7 8 9 10 11
| package _annotation;
public @interface Mystest1 { String aaa(); boolean bbb() default true; String[] ccc(); }
|
1 2 3 4 5 6 7 8 9 10 11
| package _annotation;
@Mystest1(aaa="牛魔王",ccc={"HTML","JAVA"}) public class AnnotationTest1 {
@Mystest1(aaa="铁扇公主",bbb=false,ccc={"Python","前端"}) public void test1(){
} }
|
特殊属性名: value
如果注解中只有一个value属性,使用注解时,value名称可以不写!
1 2 3 4 5
| package _annotation;
public @interface Mystest1 { String value(); }
|
1 2 3 4 5 6 7 8 9
| @Mystest1(aaa="牛魔王",ccc={"HTML","JAVA"}) @Mytest2("孙悟空") public class AnnotationTest1 {
@Mystest1(aaa="铁扇公主",bbb=false,ccc={"Python","前端"}) public void test1(){
} }
|
注解的原理
先编译为class,反编译成真正的源码
1 2 3 4 5
| public @interface Mystest1 { String aaa(); boolean bbb() default true; String[] ccc(); }
|
|
|
/
1 2 3 4 5
| public interface Mystest1 extends Annotation{ public abstract String aaa(); public abstract boolean bbb(); public abstract String[] ccc(); }
|
当我们这样写的时候:
1 2 3 4
| @Mystest1(aaa="李四",bbb=true,ccc={"Go","Python"}) public void test(){ }
|
- 注解本质是一个接口,java中所有的注解都是继承了Annotation接口的.
- @注解(…) 其实就是一个实现类对象,实现了该注解以及Annotation接口
元注解
指的是: 修饰注解的注解.
1 2 3 4 5
| @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Test { }
|

注解的解析
什么是注解的解析?
- 就是判断类上,方法上,成员变量上是否存在注解,并把注解里面的内容给解析出来.
如何解析注解?
- 指导思想: 要解析谁上面的注解,就应该先拿到谁
- 比如要解析类上面的注解,则应该先获取该类的class对象,再获取Class对象解析其上面的注解
- Class,Method,Field,Constructor,都实现了
AnnotatedElement接口,它们都拥有解析注解的能力.
| AnnotatedElement接口提供了解析注解的方法 |
说明 |
| public Annotation[] getDeclareAnnotations() |
获取当前对象上面的注解 |
public T getDeclaredAnnotation(Class<T>annotationClass) |
获取指定的注解对象 |
public boolean isAnnotatuibPresent(Class<Annotation>annotationClass) |
判断当前对象上是否存在某个注解 |
下面我们进行一个案例:
- 定义注解MyTest4,要求如
- 包含属性:String value()
- 包含属性:double aaa() 默认值为100
- 包含属性:String[] bbb()
- 限制注解使用的位置:类和成员方法上
- 指定注解的有效范围: 一直到运行时
- 定义一个类:Demo 在类中定义一个test1方法,并在该类和其方法上使用MyTest4注解
- 定义AnnotationTest3测试类,解析Demo类的全部注解.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package _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}) @Retention(RetentionPolicy.RUNTIME) public @interface MyTest4 { String value(); double aaa() default 100; String[] bbb(); }
|
1 2 3 4 5 6 7 8 9
| package _annotation; @MyTest4(value="1",aaa=99.9,bbb={"PYTHON","JAVA"}) public class demo { @MyTest4(value="2",aaa=199.9,bbb={"Go","Linux"}) public void test1(){ } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import org.junit.Test;
import java.util.Arrays;
public class AnnotationTest3 { @Test public void parseClass(){ 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())); } } }
|
结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Test public void parseMethod() throws Exception { Class c = demo.class; Method m = c.getDeclaredMethod("test1"); if(m.isAnnotationPresent(MyTest4.class)){ MyTest4 myTest4 = (MyTest4) m.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注解的方法执行.
1 2 3 4 5 6 7 8 9 10 11
| package _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 { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package _annotation;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class AnnotationTest4 {
public void test1(){ System.out.println("-----test1------"); }
@Mytest public void test2(){ System.out.println("-----test2------"); }
public void test3(){ System.out.println("-----test3------"); }
@Mytest public void test4(){ System.out.println("-----test4------"); }
public static void main(String[] args) throws Exception { AnnotationTest4 a = new AnnotationTest4(); Class c = AnnotationTest4.class; Method[] methods = c.getDeclaredMethods(); for (Method method : methods) { if(method.isAnnotationPresent(Mytest.class)){ method.invoke(a,null); } } } }
|
结果: