从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • JavaSE

  • JavaSenior

    • 反射

    • 注解

      • 什么是注解
      • 注解的本质
      • 自定义注解
      • 元注解
      • 注解练习
        • 案例:解析注解
        • 案例:简单的测试框架
      • 注解小结
    • 集合类

    • Java
  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

  • Java
  • Java
  • JavaSenior
  • 注解
2022-12-30
目录

注解练习

# 04.注解练习

‍

‍

前面我们讲反射的时候,并没有将如何获取注解,这里补充下:Field,Constructor 和 Method 类对象都可以调用下面这些方法获取标注在它们之上的注解。

  • ​Annotation[] getAnnotations()​:获取该对象上的所有注解
  • ​Annotation getAnnotation(Class annotaionClass)​:传入注解类型​​,获取该对象上的特定一个注解
  • ​Annotation[] getDeclaredAnnotations()​:获取该对象上的显式标注的所有注解,无法获取继承​​下来的注解
  • ​Annotation getDeclaredAnnotation(Class annotationClass)​:根据注解类型​​,获取该对象上的特定一个注解,无法获取继承​​下来的注解

‍

‍

# 案例:解析注解

在程序使用注解:获取注解中定义的属性值。

需求:之前用反射做了个小型的Spring框架,如今改成注解来配置。注解大多数时候都是用来替换配置文件的

定义注解:

import java.lang.annotation.*;

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

‍

定义Person类:

package com.peterjxl;

public class Person {
  public void eat(){
    System.out.println("Person eating......");
  }
}
1
2
3
4
5
6
7

‍

定义测试类 来测试

//不使用配置文件,通过注解和反射来创建对象、执行方法

import java.lang.reflect.Method;

@MyAnno5(className = "com.peterjxl.Person", methodName = "eat")
public class AnnoDemo4 {
  public static void main(String[] args) throws Exception {
    // 1. 解析注解
    // 1.1 获取该类的字节码文件对象
    Class<AnnoDemo4> annoDemo4 = AnnoDemo4.class;

    // 1.2 获取上边的注解对象
    MyAnno5 an = annoDemo4.getAnnotation(MyAnno5.class);// 指定获取什么注解

    // 2.调用注解对象中定义的抽象方法,获取返回值
    String className = an.className();
    String methodName = an.methodName();

    Class cls = Class.forName(className);// 3.加载该类进内存
    Object obj = cls.newInstance();// 4.创建对象
    Method method = cls.getMethod(methodName);// 5.获取方法对象
    method.invoke(obj); // 6.执行方法
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

‍

此时的文件目录结构:

├── AnnoDemo4.java
└── MyAnno5.java
├── com
│   └── peterjxl
│       └── Person.java
1
2
3
4
5

‍

运行结果:

javac ./com/peterjxl/Person.java
javac AnnoDemo4.java -encoding utf8 
java -cp . AnnoDemo4
Person eating......
1
2
3
4

‍

为什么能直接调用注解对象中定义的抽象方法,获取返回值? 因为实际上在内存中,生成了一个该注解的子类实现对象,即an。当于用以下类新建的的对象:

public class ProImpl implements Pro{
    public String className(){
        return "com.peterjxl.anno.Person";
    }
    public String methodName(){
        return "eat";
    }
}
1
2
3
4
5
6
7
8

‍

‍

‍

使用步骤总结:

  1. 获取注解定义的位置的对象 (Class,Method, Field)
  2. 获取指定的注解 getAnnotation(Class)​ , 其实就是在内存中生成了一个该注解接口的子类实现对象。
  3. 调用注解中的抽象方法获取配置的属性值

注意:有必检异常,需要抛出或try-catch。

‍

‍

# 案例:简单的测试框架

需求:我们要测试一个类的方法,如果每个方法都测试的话,非常麻烦,需要一个个在main方法里调用。

例如我们定义了一个计数器类:

public class Calculator {
  public void add(){
    System.out.println("1 + 0 = " + (1 + 0));
  }

  public void sub(){
    System.out.println("1 - 0 = " + (1 - 0));
  }

  public void mul(){
    System.out.println("1 * 0 = " + (1 * 0));
  }

  public void div(){
    System.out.println("1 / 0 = " + (1 / 0));
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

我们希望能在方法上加一个注解,就能实现方法的调用;如果有异常则记录到一个txt里

‍

整体思路并不难:

  1. 定义注解
  2. 创建计数器对象,获取字节码
  3. 获取所有方法
  4. 判断方法上是否有注解
  5. 有则执行,并捕获异常

‍

‍

我们先定义Check注解

import java.lang.annotation.*;

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

‍

‍

然后在计数器类里加上注解(注意show方法我们没有添加,这是测试没有注解的情况下是否会被执行)

public class Calculator {

  @Check
  public void add(){
    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

‍

‍

‍

‍

现在我们可以开始写代码,执行所有加了Check注解的方法,判断方法是否有异常,记录到bug.txt文件中

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.lang.reflect.Method;

public class AnnoDemo5 {
  public static void main(String[] args) throws Exception{
    Calculator calculator = new Calculator(); //1.创建计算器对象
    Class cls = Calculator.class;           //2.获取字节码文件对象
    Method[] methods = cls.getMethods();    //3.获取所有方法

    int exceptionNum = 0; //出现异常的次数
    BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
    for (Method method : methods) {

       //4.判断方法上是否有Check注解
      if(method.isAnnotationPresent(Check.class)){
        try {
          method.invoke(calculator); //5.有,执行
        } catch (Exception e) {
          //6.捕获异常,记录到文件中
          exceptionNum ++;
          bw.write(method.getName() + "方法出现异常了");
          bw.newLine();
          bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
          bw.newLine();
          bw.write("异常的原因:" + e.getCause().getMessage());
          bw.newLine();
        }
      }
    }

    bw.write("本次测试一共出现 " + exceptionNum + " 次异常");
    bw.flush();
    bw.close();
  }
}
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

‍

在GitHub上编辑此页 (opens new window)
上次更新: 2022/12/30 19:55:27
元注解
注解小结

← 元注解 注解小结→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式