从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

    • 反射

    • 注解

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

    • 线程

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

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

注解练习

# 注解练习

前面我们讲反射的时候,并没有将如何获取注解,这里补充下: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
上次更新: 2024/10/1 18:45:09
元注解
注解小结

← 元注解 注解小结→

最近更新
01
语雀文档一键下载至本地教程
07-04
02
要成功,就不要低估环境对你的影响
07-03
03
血泪教训:电子设备要定期开机
07-02
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式