单元测试,Junit,反射,注解(元注解,自定义注解,解析注解),动态代理


一、单元测试

单元测试就是针对最小的功能单元(方法),编写测试代码对该功能进行正确性测试。

Junit单元测试框架
JUnit是使用Java语言实现的单元测试框架

StringUtil类中新增一个测试方法

 public static int getMaxIndex(String data){
     if(data == null){
         return -1;
     }
     return data.length();
 }

在StringUtilTest类中写一个测试方法

public class StringUtilTest{
    @Test
    public void testGetMaxIndex(){
       int index1 = StringUtil.getMaxIndex(null);
       System.out.println(index1);
        
       int index2 = StringUtil.getMaxIndex("admin");
       System.out.println(index2);
        
        //断言机制:预测index2的结果
        Assert.assertEquals("方法内部有Bug",4,index2);
    }
}

优点

  • 编写的测试代码很灵活,可以指某个测试方法执行测试,也支持一键完成自动化测试。
  • 不需要程序员去分析测试的结果,会自动生成测试报告出来。
  • 提供了更强大的测试能力。

具体步骤

①将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
②编写测试类、测试类方法(注意:测试方法必须是公共的,无参数,无返回值的非静态方法)
③必须在测试方法上使用@Test注解(标注该方法是一个测试方法)
④在测试方法中,编写程序调用被测试的方法即可。
⑤选中测试方法,右键选择“JUnit运行” ,如果测试通过则是绿色;如果测试失败,则是红色

Junit单元测试框架的常用注解(Junit 5.xxxx版本)

注解说明
@Test测试方法
@BeforeEach用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次。
@AfterEach用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次。
@BeforeAll用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次。
@AfterAll用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次。

开始执行的方法:初始化资源。
执行完之后的方法:释放资源。

二、反射

1.认识反射

反射指的是允许以编程方式访问已加载类的成分(成员变量、方法、构造器等)。

反射获取的是类的信息,那么反射的第一步首先获取到类才行。由于Java的设计原则是万物皆对象,获取到的类其实也是以对象的形式体现的,叫字节码对象,用Class类来表示。获取到字节码对象之后,再通过字节码对象就可以获取到类的组成成分了,这些组成成分其实也是对象,其中每一个成员变量用Field类的对象来表示每一个成员方法用Method类的对象来表示每一个构造器用Constructor类的对象来表示

1、反射第一步:获取类:Class
2、获取类的构造器:Constructor
3、获取类的成员变量:Field
4、获取类的成员方法:Method

2.获取类

反射的关键:
反射的第一步都是先得到加载后的类,然后才可以去那类的其他成分。

反射的基本作用、关键?
反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分。
反射的核心思想和关键就是:到编译以后的class文件对象。

获取Class类的对象的三种方式

方式一:Class c1 =lass.forName(“全类名”); (源代码阶段)
方式二:Class c2 = 类名.class Class (对象阶段)
方式三:Class c3 =对象.getClass(); (Runtime运行时阶段)

3.获取类的构造器

使用反射技术获取构造器对象并使用
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

Class类中用于获取构造器的方法

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

get:获取
Declared: 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Constructor: 构造方法的意思
后缀s: 表示可以获取多个,没有后缀s只能获取一个

public class Cat{
    private String name;
    private int age;
    
    public Cat(){
        
    }
    
    private Cat(String name, int age){
        
    }
}

测试获取类中所有的构造器

public class Test2Constructor(){
    @Test
    public void testGetConstructors(){
        //1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        
        //2、获取类的全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        //3、遍历数组中的每一个构造器对象。
        for(Constructor constructor: constructors){
            System.out.println(constructor.getName()+"---> 参数个数:"+constructor.getParameterCount());
        }
    }
}

使用反射技术获取构造器对象并使用
获取构造器的作用依然是初始化一个对象返回。

Constructor类中用于创建对象的方法

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

如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象

  • setAccessible(boolean)
  • 反射可以破坏封装性,私有的也可以执行了。

由于构造器是private修饰的,先需要调用setAccessible(true) 表示禁止检查访问控制,然后再调用newInstance(实参列表) 就可以执行构造器,完成对象的初始化了。

4.获取类的成员变量

使用反射技术获取成员变量对象并使用

反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取成员变量的方法

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

get:获取
Declared: 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Field: 成员变量的意思
后缀s: 表示可以获取多个,没有后缀s只能获取一个

使用反射技术获取成员变量对象并使用
获取成员变量的作用依然是在某个对象中取值、赋值

Field类中用于取值、赋值的方法

符号说明
void set(Object obj, Object value):赋值
Object get(Object obj)获取值。

设置值、获取值的方法时Filed类的需要用Filed类的对象来调用,而且不管是设置值、还是获取值,都需要依赖于该变量所属的对象。

5.获取类的成员方法

使用反射技术获取方法对象并使用
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。

Class类中用于获取成员方法的方法

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

使用反射技术获取方法对象并使用
获取成员方法的作用依然是在某个对象中进行执行此方法

Method类中用于触发执行的方法

符号说明
Object invoke(Object obj, Object… args)运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)

6.作用

反射的作用-绕过编译阶段为集合添加数据

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

反射的作用

可以在运行时得到一个类的全部成分然后操作。
可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)

三、注解

1.概述、自定义注解

注解概述

  • Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
  • Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。

自定义注解—格式
自定义注解就是自己做一个注解来使用。

public @interface 注解名称 {
     public 属性类型 属性名() default 默认值 ;
}

注解的作用是什么
对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。
例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。

特殊属性

  • value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!
  • 但是如果有多个属性, 且多个属性没有默认值,那么value名称是不能省略的。

注解本质

注解本质上是接口,每一个注解接口都继承子Annotation接口
2.注解中的属性本质上是抽象方法
3.@MyTest1实际上是作为MyTest接口的实现类对象

2.元注解

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

元注解有两个:

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

@Target中可使用的值定义在ElementType枚举类中,常用值如下

TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造器
LOCAL_VARIABLE, 局部变量

@Target(ElementType.TYPE)	//声明@MyTest3注解只能用在类上
public @interface MyTest3{
    
}

@Retention中可使用的值定义在RetentionPolicy枚举类中,常用值如下

SOURCE: 注解只作用在源码阶段,生成的字节码文件中不存在
CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.
RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

3.注解的解析

注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。
我们把获取类上、方法上、变量上等位置注解及注解属性值的过程称为解析注解。

解析注解步骤

1.如果注解在类上,先获取类的字节码对象,再获取类上的注解
2.如果注解在方法上,先获取方法对象,再获取方法上的注解
3.如果注解在成员变量上,先获取成员变量对象,再获取变量上的注解
总之:注解在谁身上,就先获取谁,再用谁获取谁身上的注解

与注解解析相关的接口

  • Annotation: 注解的顶级接口,注解都是Annotation类型的对象
  • AnnotatedElement:该接口定义了与注解解析相关的解析方法
方法说明
Annotation[] getDeclaredAnnotations()获得当前对象上使用的所有注解,返回注解数组。
T getDeclaredAnnotation(Class annotationClass)根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class annotationClass)判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
  • 所有的类成分Class, Method , Field , Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力:

解析注解的技巧

注解在哪个成分上,我们就先拿哪个成分对象。
比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解

四、动态代理

1.概述

代理思想就是被代理者没有能力,或者不愿意去完成某件事情,需要找个人(代理)代替自己去完成这件事
动态代理主要是对被代理对象的行为进行代理。

动态代理的开发步骤

1.必须定义接口,里面定义一些行为,用来约束被代理对象和代理对象都要完成的事情。
2.定义一个实现类实现接口,这个实现类的对象代表被代理的对象。
3.定义一个测试类,在里面创建被代理对象,然后为其创建一个代理对象返回。(重点)
4.代理对象中,需要模拟收首付款,真正触发被代理对象的行为,然后接收尾款操作。
5.通过返回的代理对象进行方法的调用,观察动态代理的执行流程。

如何创建代理对象
Java中代理的代表类是:java.lang.reflect.Proxy,它提供了一个静态方法,用于为被代理对象,产生一个代理对象返回。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
为被代理对象返回一个代理对象。

参数一:类加载器 加载代理类,产生代理对象。
参数二:真实业务对象的接口。(被代理的方法交给代理对象)
参数三:代理的核心处理程序。

2.使用代理的好处

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

  • 33
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值