学习日记(单元测试、反射、注解、动态代理)

news2024/11/24 4:00:13

文章目录

  • 学习日记(单元测试、反射、注解、动态代理)
  • 一、单元测试
    • 1. 单元测试实践
    • 2. JUnit 常用注解
  • 二、反射
    • 1. 反射获取类对象
    • 2. 反射获取构造器对象
    • 3. 反射获取成员变量对象
    • 4. 反射获取成员方法对象
  • 三、反射的作用举例
    • 1. 绕过编译阶段为集合添加数据
    • 2. 通用框架
  • 四、注解
    • 1. 自定义注解
    • 2. 元注解
    • 3. 注解解析
    • 4. 注解的应用:模拟 JUnit 框架
  • 五、动态代理
    • 1. 案例 1
    • 2. 案例 2
  • 注意:

学习日记(单元测试、反射、注解、动态代理)

一、单元测试

单元测试就是针对最小的功能单元编写测试代码,Java 程序最小的功能单元是方法

单元测试就是针对 Java 方法的测试,进而检查方法的正确性,需要用到 JUnit 单元测试框架。

JUnit 单元测试框架是使用 Java 语言实现的,是开源的,几乎所有的 IDE 工具都集成了 JUnit。

JUnit 单元测试框架的优点

  • JUnit 可以灵活地选择执行哪些测试方法,也可以一键执行全部测试方法;
  • JUnit 可以生成全部方法的测试报告,测试良好为绿色,测试失败为红色;
  • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

1. 单元测试实践

使用单元测试进行业务方法预期结果、正确性的测试,步骤

  • 将 JUnit 的 jar 包导入到项目中,IDEA 通常整合好了 JUnit 框架,一般不需要导入;
  • 单独创建一个测试类,编写测试方法,每个测试方法必须是公共的、无参数、无返回值的非静态方法;
  • 在测试方法上使用 @Test 注解,第一次使用时需要 Alt + Enter 导入包 org.junit.Test,标注该方法是一个测试方法;
  • 在测试方法中完成被测试方法的预期正确性测试,选择测试方法,选择“ JUnit 运行”。
方法名说明
public static void assertEquals(String message, long expected, long actual)断言,类 Assert 直接调用

说明:参数一是预期值与实际值不相同时,给出的提示信息;参数二是预期值;参数三是实际值。

当没有问题时

当出现问题时

注意

  • 测试类和测试方法的命名应该规范。

  • 每个测试方法必须是公共的无参数无返回值非静态方法。

  • 测试方法应该使用 @Test 注解标记。

  • 一个业务方法对应一个测试方法。

  • 运行测试方法时,可以单独测试方法,也可以一起测试所有方法。

2. JUnit 常用注解

JUnit 4 版本

注解说明
@Test测试方法
@Before用来修饰实例方法,该方法会在每一个测试方法执行之前执行一次
@After用来修饰实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass用来修饰静态方法,该方法会在所有测试方法执行之前只执行一次
@AfterClass用来修饰静态方法,该方法会在所有测试方法执行之后只执行一次

注意

  • 开始执行的方法:一般用来完成初始化资源;
  • 执行完之后的方法:一般用来释放资源。

二、反射

反射是在运行时获取类的字节码文件对象,然后可以解析这个类的全部成分。

在运行时,可以直接得到这个类的构造器对象(Constructor)、成员变量对象(Field)、成员方法对象(Method)。

这种运行时动态获取类信息以及动态调用类中成分的能力称为 Java 语言的反射机制。

反射的核心思想和关键:得到编译后的 Class文件对象。

反射的作用

  • 可以在运行时得到一个类的全部成分然后操作;
  • 可以破坏封装性;
  • 可以破坏泛型的约束性。

反射适合的用途:做 Java 的高级框架。

1. 反射获取类对象

反射的第一步是先得到编译后的 Class 类对象,有三种方法。

  • 方法一:调用 Class 类中的一个静态方法 forName
  • 方法二:类调用 class 方法。
  • 方法三:对象调用 getClass 方法获取对应类的 Class 对象。
方法名说明
方法一public static Class<?> forName(String className)Class 类调用
方法二class调用
方法三public final native Class<?> getClass()对象调用

注意:方法一中的参数为全限名,也就是包名 + 类名。

2. 反射获取构造器对象

总体步骤

  • 获得 Class 对象;
  • (通过 Class 对象)获得构造器 Constructor 对象;
  • (通过构造器)创建对象。

第二步:Class 类获得构造器 Constructor 对象的方法:

方法名说明
public Constructor<?>[] getDeclaredConstructors()返回所有构造器对象的数组,存在就能拿到
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造器对象,存在就能拿到

注意

  • 这两个方法都是 Class 对象调用。

  • 这两个方法获取构造器,无所谓构造器的声明类型,即,无所谓构造器是 public 还是 private。

  • 返回单个构造器对象时,方法的参数为 Class 对象且为可变参数,如:String.classint.class

  • 返回单个构造器对象时,若不写参数,则返回无参构造器,有参数,返回有参构造器。

第三步:创建对象的方法:

方法名说明
public T newInstance(Object … initargs)根据指定的构造器创建对象
public void setAccessible(boolean flag)参数设置为 true,表示取消访问检查,进行暴力反射

注意

  • 这两个方法都是构造器对象调用。
  • 第二个方法是当构造器方法不是用 public 修饰时使用,打开权限,可以有效一次,反射可以破坏封装性,私有的也可以执行。
  • 第一个方法中,当构造器为无参时,方法不写参数;当构造器为有参时,方法中的参数为初始化值。

第二步代码示例:获取所有构造器对象的数组、获取单个构造器对象

第三步代码示例:初始化对象、暴力反射

3. 反射获取成员变量对象

总体步骤

  • 获得 Class 对象;
  • (通过 Class 对象)获得成员变量 Field 对象;
  • (通过成员变量)赋值或者取值。

第二步:Class 类获得成员变量 Field 对象的方法:

方法名说明
public Field[] getDeclaredFields()返回所有成员变量对象的数组,存在就能拿到
public Field getDeclaredField(String name)返回单个成员变量对象,存在就能拿到

注意

  • 这两个方法都是 Class 对象调用。

  • 这两个方法获取成员变量对象,无所谓成员变量的声明类型,即,无所谓成员变量是 public 还是 private。

  • 第二个方法的参数为成员变量的名称,即属性的名称。

第三步:赋值或者取值的方法:

方法名说明
public void set(Object obj, Object value)赋值
public Object get(Object obj)取值
public void setAccessible(boolean flag)参数设置为 true,表示取消访问检查,进行暴力反射

注意

  • 这三个方法都是成员变量对象调用。
  • 当成员变量对象不是用 public 修饰时使用 setAccessible,打开权限,反射可以破坏封装性,私有的也可以执行。
  • 在赋值方法中,参数一是创建的对象,参数二是为该对象指定的属性赋值。

第二步代码示例:获取所有成员变量对象的数组、获取单个成员变量对象

第三步代码示例:赋值、取值、暴力反射

4. 反射获取成员方法对象

总体步骤

  • 获得 Class 对象;
  • (通过 Class 对象)获得成员方法 Method 对象;
  • (通过成员方法对象)运行方法。

第二步:Class 类获得成员方法对象的方法:

方法名说明
public Method[] getDeclaredMethods()返回所有成员方法对象的数组,存在就能拿到
public Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象,存在就能拿到

注意

  • 这两个方法都是 Class 对象调用。

  • 这两个方法获取成员方法对象,无所谓成员方法的声明类型,即,无所谓成员方法是 public 还是 private。

  • 第二个方法的第一个参数为:方法名;第二个参数为:该方法参数类型的 Class 对象,如:int.class,若该方法没有参数,则可以不写第二个参数。

第三步:运行方法:

方法名说明
public Object invoke(Object obj, Object… args)运行方法
public void setAccessible(boolean flag)参数设置为 true,表示取消访问检查,进行暴力反射

注意

  • 这三个方法都是成员方法对象调用。
  • 当成员方法对象不是用 public 修饰时使用 setAccessible,打开权限,反射可以破坏封装性,私有的也可以执行。
  • 第一个方法的第一个参数:对象;第二个参数:传递的参数(如果没有参数可以不写)。

第二步代码示例:获取所有成员方法对象的数组、获取单个成员方法对象

第三步代码示例:运行方法、暴力反射


三、反射的作用举例

1. 绕过编译阶段为集合添加数据

泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList,泛型相当于被擦除,此时,可以为集合存入其他任意类型的元素,这就用到了反射,因为反射是在运行的技术

通过反射为集合添加其他类型的数据

2. 通用框架

需求:给定任意一个对象,在不清楚对象字段的情况下,可以把对象的字段名称和对应值存储到文件中去。

分析

  • 定义一个类 MybatisUtil 存放 save 方法,可以接收任意类型的对象;
  • save 方法中,应用反射获取该对象的全部成员变量名称以及对应值;
  • 用打印流 PrintStream 将获取的数据写入到文件中;
  • main 方法中对象调用 save 方法,得到目标文件。

注意

  • 当成员变量是非公有属性时,要用 setAccessible 来打开权限,暴力反射。
  • Class 对象获取类名的两个方法,如下:
方法名说明
public String getName()获取当前 Class 对象的全限名:包名 + 类名
public String getSimpleName()获取当前 Class 对象的类名


四、注解

注解:Annotation,又称标注。Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。

作用:对 Java 中类、构造器、方法、成员变量、参数等做标记,然后进行特殊处理。

例如在 JUnit 框架中,标注了注解 @Test 的方法就可以被当作测试方法执行,而没有标记的就不能当作测试方法执行。

1. 自定义注解

格式

类、构造器、方法、成员变量、参数等都可以被注解进行标注。

特殊属性 value

  • value 属性,如果自定义注解时只有一个 value 属性的情况下,使用 value 属性可以省略 value 名称不写。
  • 如果有多个属性,并且多个属性都有默认值,那么 value 名称也可以省略不写。
  • 除了上面两种情况外,value 的名称都得写。

2. 元注解

元注解:注解注解的注解。

两个元注解:

  • @Target :约束自定义注解只能在哪些地方使用。
  • @Retention :声明注解的生命周期。

3. 注解解析

注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。

与注解解析相关的接口:

  • Annotation :注解的顶级接口,注解都是该类型的对象;
  • AnnotationElement :该接口定义了与注解解析相关的解析方法。

Class、Method、Field、Constructor 这些类都实现了 AnnotationElement 接口,都拥有解析注解的能力。

解析注解的方法

方法名说明
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)判断当前对象是否使用了指定的注释
public A getDeclaredAnnotation(Class annotationClass)根据注解类型获得对应的注解对象
public Annotation[] getDeclaredAnnotations()获得当前对象所有注解,返回注解数组

注意:方法一和方法二都是由 Class、Method、Field、Constructor 这些类对象调用,参数为注解的类类型,如:Book.class

解析注解的技巧:注解在哪个成分上,就先拿哪个成分对象。

  • 注解作用在类上,就先获得该类对应的 Class 对象,然后再拿注解;
  • 注解作用在成员方法上,就先获得该成员方法对应的 Method 对象,然后再拿注解;
  • 注解作用在成员变量上,就先获得该成员变量对应的 Field 对象,然后再拿注解。

4. 注解的应用:模拟 JUnit 框架

需求:自定义一个注解 MyTest,和 JUnit 框架一样,只有方法上有 MyTest 注解才可以被执行。

思路:先用反射提取类中的所有方法,用循环依次判断每一个方法是否有 MyTest 注解,有注解然后执行。


五、动态代理

代理也是一个对象,用来对被代理对象的行为额外做一些辅助操作

Java 中代理的类是:java.lang.reflect.Proxy,类中有一个静态方法 newProxyInstance,可以为对象产生一个代理对象返回。

方法名说明
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)为对象返回代理对象

注意

  • 参数一:是定义代理类的类加载器,用来产生代理对象,如:dog.getClass().getClassLoader()
  • 参数二:是代理类要实现的接口列表,用来将被代理的方法交给代理对象,如:dog.getClass().getInterfaces()
  • 参数三:是代理对象的核心处理程序,用来指定代理对象干什么事,如:new InvocationHandler()

实现动态代理的步骤

  • 必须存在接口,且被代理对象需要实现接口;
  • 使用 Proxy 类提供的方法 newProxyInstance,产生一个代理对象。

动态代理的优点

  • 可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用;
  • 简化了编程工作,提高了开发效率,同时提高了软件系统的可扩展性;
  • 可以为被代理对象的所有方法做代理;
  • 非常灵活,支持为任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。

1. 案例 1

需求:为 dog 对象创建一个代理对象。

注意点

  • 最好将产生代理对象的方法封装到一个类中。
  • 必须存在接口,并且被代理对象需要实现接口,代理对象的类型为接口。
  • 通过代理对象调用方法的执行流程:先走向代理;代理可以为方法额外做一些辅助工作;用 method 去触发对象方法的执行;回到代理中,由代理负责返回结果给方法的调用者。执行流程图如下。
  • method 去触发对象,method 是正在调用的方法,args 是该方法的参数,固定步骤

2. 案例 2

需求:模拟用户管理业务,包括用户登录、用户删除、用户查询功能,做性能分析,统计每个功能的耗时。

分析:把性能分析交给代理去统一完成,这样可以省去在每个方法中都进行一遍性能分析,提高了代码的复用性。

注意:必须要有接口,并且实现类要实现接口,代理通常是基于接口实现的。


注意:

  1. 通过这种方式也可以为集合添加其他类型的元素。

对比

  1. 动态代理非常灵活,支持为任意接口类型的实现类对象做代理,也可以直接为接口本身做代理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/21003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于生物地理学的优化算法(BBO)用于训练多层感知器(MLP)【多种算法进行比较】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

java中的BigDecimal使用

文章目录1、什么是BigDecimal&#xff1f;2、为什么使用BigDecimal&#xff1f;3、如何使用BigDecimal&#xff1f;&#xff08;1&#xff09;BigDecimal初始化赋值&#xff08;2&#xff09;加减乘除运算&#xff08;3&#xff09;BigDecimal保留两位小数及舍入模式&#xff0…

WFP实现侧边栏导航菜单

菜单导航功能实现&#xff0c;常规的管理系统应该常用&#xff0c;左侧显示菜单条目&#xff0c;点击菜单&#xff0c;右侧切换不同的业务用户控件。 常用菜单可以采用TreeView树形控件特定样式实现 &#xff0c;本文介绍的是使用ExpanderListView的组合形式实现的导航菜单&am…

算法day24|理论基础77

详细布置 理论基础 什么是回溯法&#xff1a;递归函数下面通常有回溯法 它使用的地方&#xff1a;组合&#xff0c;切割&#xff0c;子集&#xff0c;排列&#xff0c;棋盘问题&#xff08;N皇后&#xff0c;解数独&#xff09; 回溯算法的模板: void backtracking(参数)&…

微型计算机基础

微型计算机常用术语 位&#xff08;bit&#xff09;&#xff1a;计算机所能表示的最基本&#xff0c;最小的数据单元。1个二进制位有两种状态0和1 通常情况下0表示低电平&#xff08;接地&#xff09;&#xff0c;1表示高电平接电源&#xff08;VCC&#xff09; 字节&#xff0…

MATLAB 矩阵处理及多项式计算

一、实验目的 &#xff08;1&#xff09;掌握生成特殊矩阵以及矩阵处理的方法 &#xff08;2&#xff09;掌握数据统计和分析的方法 &#xff08;3&#xff09;掌握多项式的常用计算 二、实验原理与实验设备 原理&#xff1a;计算机编程相关知识技能和MATLAB软件编译环境 …

c++——map和set的封装

注&#xff1a;该封装基于前面博客已实现红黑树&#xff0c;map和set封装并不难&#xff0c;主要还是对红黑树的理解 目录 一. 改造红黑树 1. 改变节点的定义&#xff0c;使用更高维度的泛型 2. 红黑树追加迭代器的实现 1. 红黑树迭代器的构造函数和基本框架 2. begin()和e…

2.4、编码与调制

2.4、编码与调制 在计算机网络中。计算机需要处理和传输用户的文字&#xff0c;图片&#xff0c;音频和视频。它们可以统称为消息。 数据是运送消息的实体。 计算机中的网卡将比特 000 和 111&#xff0c;变换成相应的电信号发送到网线。 也就是说&#xff0c;信号是数据的…

[附源码]java毕业设计网络学习平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

LeetCode力扣刷题——更加复杂的数据结构

更加复杂的数据结构 一、引言 目前为止&#xff0c;我们接触了大量的数据结构&#xff0c;包括利用指针实现的三剑客和 C 自带的 STL 等。 对于一些题目&#xff0c;我们不仅需要利用多个数据结果解决问题&#xff0c;还需要把这些数据结构进行嵌套和联 动&#xff0c;进行更为…

五.STM32F030C8T6 MCU开发之RTC模块基础例程

五.STM32F030C8T6 MCU开发之RTC模块基础例程 文章目录五.STM32F030C8T6 MCU开发之RTC模块基础例程0.总体功能概述1.RTC硬件介绍1.1日历的功能1.2 闹钟输出1.3 入侵检测1.4 时间戳事件检测2.RTC软件配置2.1.RTC 模块初始化配置2.2 RTC 开始时间配置2.2.1RTC 年月日 时分秒配置2.…

_linux 进程间通信(管道)

文章目录1. 进程间通信目的2. 进程间通信发展3. 进程间通信分类4. 管道1. 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#x…

【English】十大词性之介词

介词 文章目录介词前言一、方位介词1.1 某地1.2 里里外外1.3 上上下下1.4 前前后后1.5 ....中间1.6 ...穿越1.7 ...树上1.8 在...墙上1.9 旁边(距离远近区分)二、时间介词三、方式介词四、易混淆介词4.1 制成4.2 交通工具4.3 除了总结前言 介词是表示名词、代词与句子中其它词…

02Java线程模型

1. 操作系统线程 无论使用何种编程语言编写多线程程序&#xff0c;最终都是通过调用操作系统的线程来执行任务。线程是CPU调度的最小执行单元。 线程有多种实现方式&#xff0c;常见的有&#xff1a;内核线程、用户线程、混合线程。 不同线程模型的主要区别在于线程的调度方不…

【Ubuntu】配置ubuntu网络

配置ubuntu网络 一、三种虚拟网络介绍二、 配置ubuntu系统使用桥接模式连接外网三、通过NAT模式让ubuntu系统连接外网四、常见问题1.解决ubuntu系统没有网络图标一、三种虚拟网络介绍 VMnet0 : 桥接模式,选中桥接模式之后,可以将VMnet0桥接到对应的物理网卡之上, 默认选中自…

uniapp公共新闻模块components案例

uniapp公共新闻模块components案例 简介&#xff1a;本文使用uniapp的公共新闻模块讲解components案例。 效果展示&#xff1a; 第一步 创建公共模块 第二步 编写组件 <template><view class"newsbox"><view class"pic"><ima…

动态路由协议 OSPF 工作过程 之 状态机维度

状态机 &#xff1a; # 什么是状态机呢 &#xff1f; 状态机 &#xff1a; 就是 OSPF 路由间的邻居关系所在的不同阶段 不同的关系 就是 不同的状态机 OSPF 的状态机 &#xff1a; # 我们用 思科 的PPT 来介绍 OSPF 的状态机 # 里面所有黄颜色方框里 标定的就是 状态机…

Json格式API调试,taobao1688pinduoduo商品详情测试接口

Json常用类型 任何支持的类型都可以通过 JSON 来表示&#xff0c;例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型。 对象&#xff1a;对象在 JS 中是使用花括号包裹 {} 起来的内容&#xff0c;数据结构为 {key1&#xff1a;value1, key2&#xf…

JavaScript:生成器函数

在介绍生成器函数之前先了解一下ES6的一个关键字&#xff0c;名为yield yield关键字&#xff0c;可以让代码在其出现的地方暂停执行&#xff0c;它只能在生成器函数内部使用。 生成器函数 生成器函数的语法比较简单在普通函数声明的时候在函数名前面添加一个*即可&#xff0…

openxr runtime Monado 源码解析 源码分析:Prober设备发现和管理 system device HMD target instance

monado系列文章索引汇总&#xff1a;openxr runtime Monado 源码解析 源码分析&#xff1a;源码编译 准备工作说明 hello_xr解读openxr runtime Monado 源码解析 源码分析&#xff1a;整体介绍 模块架构 模块作用 进程 线程模型 整体流程openxr runtime Monado 源码解析 源码分…