14.Java的注解

一.Java注解

  • 定义:JDK1.5之后引入的新特性,用来说明程序给计算机看的。
  • 作用:编译检查,编写文档,代码分析

1.Java中的内置注解

Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

  • 作用在代码的注释:

    • @Override:检测被该注解标注的方法是否是继承自父类(父接口)的
    • @Deprecated:该注释标注的内容表示已经过时了
    • @SuppressWarnings:压制警告
      • 一般传递参数all:@SuppressWarnings("all") 表示压制所有警告
  • 作用在其他地方注解
    • 元注解:
      • @Target:标记注解作用的位置(作用在类上还是方法上还是成员变量上)。
        • ElementType取值:
          • TYPE:作用在类上
          • METHOD:作用在方法上
          • FIELD:作用在成员变量上
      • @Retention:标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
        • RetentionPolicy取值:
          • SOURCE:不会被保留在字节码文件中
          • CLASS:保留到class字节码文件中,不会被JVM读取到
          • RUNTIME:保留到class字节码文件中,并被JVM读取到(常用)
      • @Documented:描述注解是否被抽取到api文档中。
      • @Inherited:描述注解是否被子类继承(表示子类是否会自动继承父类注解)
    • 从 Java 7 开始,额外添加了 3 个注解:
      • @SafeVarargs:Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
      • @FunctionalInterface:Java 8 开始支持,标识一个匿名函数或函数式接口。
      • @Repeatable:Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

2.自定义注解

  • 基本格式:
    1 元注解
    2 public @interface 注解名称{
    3     属性列表
    4 }
    开头编写元注解,下面编写自己的注解
  • 本质:注解本质就是一个接口,该接口默认继承Annotation接口
    • public interface MyAnno extends java.lang.annotation.Annotation{}
  • 属性:接口中抽象方法
    • 要求:
      • 属性的返回类型
        • 8大基本类型
        • String
        • 枚举
        • 注解
        • 以上类型的数组
      • 使用注解时需要给属性进行赋值
        • 如果定义属性时使用default给属性赋默认值后,使用注解时可以不对属性进行赋值
        • 如果只有一个属性需要赋值,并且属性名为value时,value可以省略,直接给值即可。
        • 数组赋值时,值使用{}包裹,如果数组至于一个值,则{}可以省略

Anno2:

1 public @interface Anno2 {
2     String name();
3 }

MyEnum:

1 public enum MyEnum {
2     type1,type2
3 }

MyAnno:

1 public @interface MyAnno {
2     int age();
3     String name() default "张三";
4     MyEnum type();
5     Anno2 anno2();
6     String[] strs();
7 }

TestAnno:

1 @MyAnno(age = 24, type = MyEnum.type1, anno2 = @Anno2(name = "anno2"), strs = {"s1", "s2"})
2 public class TestAnno {
3 
4 }

3,在程序使用(解析)注解:获取注解定义的属性值

  • 步骤:
    • 获取注解定义的位置的对象(Class,Method,Field)
    • 获取指定的注解
      • getAnnotation(Class):实质上是在内存中生成了一个该注解的接口的子类实现对象
    • 调用注解中的抽象方法获取到配置的属性

注解类:Pro

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 public @interface Pro {
4 
5     String className();
6     String methodName();
7     String parameterType();
8 }

需要生成的类:TestClass

1 public class TestClass {
2     private void show(String s){
3         System.out.println(s);
4     }
5 }

主类:ReflectTest

 1 @Pro(className = "day11.TestClass",methodName = "show",parameterType = "java.lang.String")
 2 public class ReflectTest {
 3 
 4     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
 5 
 6         //1.解析注解
 7         //1.1获取该类的字节码文件对象
 8         Class<ReflectTest> reflectTestClass = ReflectTest.class;
 9         //2.获取注解对象
10         Pro an = reflectTestClass.getAnnotation(Pro.class);
11         //实质上是在内存中生成了一个该注解的接口的子类实现对象
12 /*
13         public class ProImpl implements Pro{
14             public String className(){
15                 return "day11.TestClass";
16             }
17 
18             public String methodName(){
19                 return "show";
20             }
21 
22             public String parameterType(){
23                 return "java.lang.String";
24             }
25         }
26 */
27 
28         //3.调用注解对象中定义的抽象方法,获取返回值
29         String className = an.className();
30         String methodName = an.methodName();
31         Class parameterType = Class.forName(an.parameterType());
32 
33         //4.加载该类进内存
34         Class cls = Class.forName(className);
35 
36         //5.创建对象
37         Object obj = cls.newInstance();
38 
39         //6.获取方法对象
40         Method method = cls.getDeclaredMethod(methodName,parameterType);
41         method.setAccessible(true);
42 
43         //7.执行方法
44         method.invoke(obj,"day11.TestClass--show");
45     }
46 }

结果:

4.案例:简单的测试框架

注解类:Check

1 @Target(ElementType.METHOD)
2 @Retention(RetentionPolicy.RUNTIME)
3 public @interface Check {
4 }

计算器类:Calculator

 1 public class Calculator {
 2 
 3     //加法
 4     @Check
 5     public void add() {
 6         System.out.println("1 + 0 =" + (1 + 0));
 7     }
 8 
 9     //减法
10     @Check
11     public void sub() {
12         System.out.println("1 - 0 =" + (1 - 0));
13     }
14 
15     //乘法
16     @Check
17     public void mul() {
18         System.out.println("1 * 0 =" + (1 * 0));
19     }
20 
21     //除法
22     @Check
23     public void div() {
24         System.out.println("1 / 0 =" + (1 / 0));
25     }
26 
27     //不检测的方法
28     public void show() {
29         System.out.println("不检测的方法");
30     }
31 }

测试Check类:TestCheck

public class TestCheck {

    public static void main(String[] args) throws IOException {

        //1.创建计算器对象
        Calculator c = new Calculator();
        //2.获取字节码文件对象
        Class cls = c.getClass();
        //3.获取所有方法
        Method[] methods = cls.getMethods();

        //记录出现异常次数
        int number = 0;
        //将异常信息记录在bug.txt中
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));

        for (Method method : methods) {

            //4.判断方法上是否有Check注解
            if (method.isAnnotationPresent(Check.class)) {
                try {

                    //5.有Check注解,执行
                    method.invoke(c);
                } catch (Exception e) {

                    //6.捕获异常
                    //记录异常信息
                    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.write("本次测试一共出现" + number + "次异常");
        bw.flush();
        bw.close();
    }
}

结果:

5.小结:

  • 大多数情况下是使用注解而不是自定义注解
  • 注解是给编译器和解析程序用的
  • 注解不是程序的一部分,可以理解为注解就是一个标签
原文地址:https://www.cnblogs.com/zhihaospace/p/12227723.html