注解
何谓注解
Annotation
(注解) 是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量,提供某些信息供程序在编译或者运行时使用。
注解本质是一个继承了Annotation
的特殊接口:
1 2 3 4 5 6 7
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
public interface Override extends Annotation{ }
|
作用分类
编写文档
通过代码里标识的注解生成文档【生成文档doc文档】
创建java文件 Annotation.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public class AnnoDemo1 {
public int add(int a,int b){ return a + b; } }
|
命令行输出javadoc AnnoDemo1.java
生成了doc文档
编译期直接扫描
编译器在编译 Java 代码的时候扫描对应的注解并处理,比如某个方法使用@Override
注解,编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。
JDK中预定义的一些注解
@Override :检测被该注解标注的方法是否是继承自父类(接口)的
@Deprecated:该注解标注的内容,表示已过时
@SuppressWarnings:压制警告,一般传递参数all @SuppressWarnings(“all”)
运行期通过反射处理
像框架中自带的注解(比如 Spring 框架的 @Value
、@Component
)都是通过反射来进行处理的。
自定义注解
1 2 3
| public @interface 注解名称{ 属性列表; }
|
注解的属性
注解可以包含一些属性,这些属性是注解的一部分,用于提供更多的信息或配置。
注解的属性定义类似于接口的方法,可以包含返回类型和参数列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public enum Person { P1,P2,P3; }
public @interface MyAnno { int age(); Person per(); MyAnno2 anno2(); String[] strs(); String name() default "张三"; }
@MyAnno(age = 12,per = Person.P1, anno2 = @MyAnno2,strs = {"aaa","bbb"}) public class Worker { }
|
元注解
用于描述注解的注解,注解本身也可以被注解,这种注解称为元注解。元注解用于定义注解的行为,例如指定注解的生命周期、作用目标等
@Target:描述注解能够作用的位置,@Target({ElementType.属性, ElemnetType.属性,…})
ElementType取值:
- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
@Retention:描述注解被保留的阶段:@Retention(RetentionPolicy.属性)
RetentionPolicy取值:
- SOURCE: 源码阶段
- CLASS : 类对象阶段
- RUNTIME:运行阶段,当前被描述的注解,会保留到class字节码文件中,并被JVM读取到,一般都写这一种
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承
1 2 3 4 5 6 7
| @Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface MyAnno3 {
}
|
AnnotatedElement接口
是Java反射API中的一个接口,定义了用于获取关于程序元素(类、方法、字段等)上注解信息的一组方法。AnnotatedElement 接口的实现类主要包括 Class 类、Method 类、Constructor 类、Field 类等
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public interface AnnotatedElement { boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
Annotation[] getAnnotations();
Annotation[] getDeclaredAnnotations(); }
|
运行时解析注解
- 获取注解定义的位置的对象的Class类型,这个对象可以是类,方法,或成员变量(Class,Method,Field)
- 获取指定的注解,Class.getAnnotation(Class< T> annotationClass):参数为注解的Class类型
- 调用注解中的抽象方法获取配置的属性值
现有一个类和方法
1 2 3 4 5
| public class Demo1 { public void show(){ System.out.println("demo1...show"); } }
|
写一个自定义注解
1 2 3 4 5 6 7 8 9
|
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Pro { String className(); String methodName(); }
|
写一个需要使用注解的类
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
| @Pro(className = "annotation.Demo1",methodName = "show") public class ReflectTest { public static void main(String[] args) throws Exception {
Class<ReflectTest> reflectTestClass = ReflectTest.class;
Pro proimpl = reflectTestClass.getAnnotation(Pro.class);
String className = proimpl.className(); String methodName = proimpl.methodName(); System.out.println(className); System.out.println(methodName);
Class cls = Class.forName(className); Object obj = cls.newInstance(); Method method = cls.getMethod(methodName); method.invoke(obj); } }
|
其实就是在内存中生成了一个该注解接口的子类实现对象
1 2 3 4 5 6 7 8
| public class ProImpl implements Pro{ public String className(){ return "cn.itcast.annotation.Demo1"; } public String methodName(){ return "show"; } }
|
检查注解是否存在
pubulic boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):用于检查特定的注解是否应用于类、方法、字段或其他程序元素。
当主方法执行后,会自动自行被检测的所有方法(加了Check注解的方法),判断方法是否有异常,记录到文件中
1 2 3 4
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Check { }
|
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
| public class Calculator { @Check public void add(){ String str = null; str.toString(); System.out.println("1 + 0 =" + (1 + 0)); } @Check public void sub(){ System.out.println("1 - 0 =" + (1 - 0)); } @Check public void mul(){ System.out.println("1 * 0 =" + (1 * 0)); } @Check public void div(){ System.out.println("1 / 0 =" + (1 / 0)); }
public void show(){ System.out.println("永无bug..."); } }
|
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
| public class TestCheck { public static void main(String[] args) throws IOException { Calculator c = new Calculator(); Class cls = c.getClass(); Method[] methods = cls.getMethods();
int number = 0; BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) { if(method.isAnnotationPresent(Check.class)){ try { method.invoke(c); } catch (Exception e) { number ++; bw.write(method.getName()+ " 方法出异常了"); bw.newLine(); bw.write("异常的名称:" + e.getCause().getClass().getSimpleName()); bw.newLine(); bw.write("异常的原因:"+e.getCause().getMessage()); bw.newLine(); bw.write("--------------------------"); bw.newLine(); } } } bw.write("本次测试一共出现 "+number+" 次异常"); bw.flush(); bw.close(); } }
|
生成了bug.txt