当前位置: 首页 > news >正文

java高级之单元测试、反射

1、Junit测试工具

@Test定义测试方法
1.被@BeforeClass标记的方法,执行在所有方法之前
2.被@AfterCalss标记的方法,执行在所有方法之后
3.被@Before标记的方法,执行在每一个@Test方法之前
4.被@After标记的方法,执行在每一个@Test方法之后

public class StringUtilTest{@Beforepublic void test1(){System.out.println("--> test1 Before 执行了");}@BeforeClasspublic static void test11(){System.out.println("--> test11 BeforeClass 执行了");}@Afterpublic void test2(){System.out.println("--> test2 After 执行了");}@AfterCalsspublic static void test22(){System.out.println("--> test22 AfterCalss 执行了");}
}

2、反射

定义:反射技术,指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)

2.1、获得class对象(字节码对象)

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

获取Class对象的三种方式

  • Class c1=类名.class
  • 调用Class提供方法:public static Class forName(String package);
  • Object提供的方法: public Class getClass();Class c3=对象getClass();

2.2 获取类的构造器

Class提供了从类中获取构造器的方法
方法
Constructor<?>[] getConstructors() 获取全部构造器(只能获取public修饰的)
Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到)
Constructor<T> getConstructor(Class<?>... parameterTypes) 获取某个构造器(只能获取public修饰的)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取某个构造器(只要存在就能拿到)get:获取
Declared: 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Constructor: 构造方法的意思
后缀s: 表示可以获取多个,没有后缀s只能获取一个

2.3获取构造器的作用

获取类构造器的作用: 依然是初始化对象返回
Constructor提供的方法
T newInstance(Object... initargs)(可以是有的任意参数数量)调用此构造器对象表示的构遣器,并传入参数,完成对象的初始化并返回public void  setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)

2.4 反射获取成员变量&使用

Class提供了从类中获取成员变量的方法
方法
public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的)
public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)
public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的)
public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)
获取到成员变量的作用: 依然是赋值、取值。
方法
void set(Object obj,object value): 赋值(需要传入对象,不然不知道为哪个对象赋值)
object get(Object obj) 取值
public void  setAccessible(boolean flag)  设置为true,表示禁止检查访问控制 (暴力反射)

2.5成员方法的获取和取值

获取类的成员方法
Class提供了从类中获取成员方法的API。
方法
Method[] getMethods() 获取类的全部成员方法(只能获取public修饰的)
Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到)
Method getMethod(String name, Class<?>... parameterTypes) 获取类的某个成员方法(只能获取public修饰的)
Method getDeclaredMethod(String name, Class<?>.. parameterTypes) 获取类的某个成员方法(只要存在就能拿到)成员方法的作用: 依然是执行
Method提供的方法
public Object invoke(Object obj,Object... args) 触发某个对象的该方法执行。
public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)

public class Test3Method{
public static void main(String[] args){
//1、反射第一步:先获取到Class对象
Class c = Cat.class;

    //2、获取类中的全部成员方法Method[] methods = c.getDecalaredMethods();//3、遍历这个数组中的每一个方法对象for(Method method : methods){System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType());}System.out.println("-----------------------");//4、获取private修饰的run方法,得到Method对象Method run = c.getDecalaredMethod("run");//执行run方法,在执行前需要取消权限检查Cat cat = new Cat();run.setAccessible(true);Object rs1 = run.invoke(cat);System.out.println(rs1)//5、获取private 修饰的eat(String name)方法,得到Method对象Method eat = c.getDeclaredMethod("eat",String.class);eat.setAccessible(true);Object rs2 = eat.invoke(cat,"鱼儿");System.out.println(rs2)
}

}

获取运行返回结果
在这里插入图片描述

2.6 反射的作用

反射使用来写框架的,也就是不管输入的什么类型的对象,我们都可以获取对应的class文件去做一些统一的处理。下面让我们写一个框架,能够将任意一个对象的属性名和属性值写到文件中去。不管这个对象有多少个属性,也不管这个对象的属性名是否相同。

1.先写好两个类,一个Student类和Teacher2.写一个ObjectFrame类代表框本架在ObjectFrame类中定义一个saveObject(Object obj)方法,用于将任意对象存到文件中去参数:Object obj: 就表示要存入文件中的对象3.编写方法内部的代码,往文件中存储对象的属性名和属性值1)参数obj对象中有哪些属性,属性名是什么实现值是什么,中有对象自己最清楚。2)接着就通过反射获取类的成员变量信息了(变量名、变量值)3)把变量名和变量值写到文件中去

写一个ObjectFrame表示自己设计的框架,代码如下图所示

public class ObjectFrame{public static void saveObject(Object obj) throws Exception{PrintStream ps = new PrintStream(new FileOutputStream("模块名\\src\\data.txt",true));//1)参数obj对象中有哪些属性,属性名是什么实现值是什么,中有对象自己最清楚。//2)接着就通过反射获取类的成员变量信息了(变量名、变量值)Class c = obj.getClass(); //获取字节码ps.println("---------"+class.getSimpleName()+"---------");Field[] fields = c.getDeclaredFields(); //获取所有成员变量//3)把变量名和变量值写到文件中去for(Field field : fields){String name = field.getName();Object value = field.get(obj)+"";ps.println(name);}ps.close();}
}

使用自己设计的框架,往文件中写入Student对象的信息和Teacher对象的信息。

先准备好Student类和Teacher类

public class Student{private String name;private int age;private char sex;private double height;private String hobby;
}
public class Teacher{private String name;private double salary;
}

创建一个测试类,在测试中类创建一个Student对象,创建一个Teacher对象,用ObjectFrame的方法把这两个对象所有的属性名和属性值写到文件中去。

public class Test5Frame{@Testpublic void save() throws Exception{Student s1 = new Student("黑马吴彦祖",45, '男', 185.3, "篮球,冰球,阅读");Teacher s2 = new Teacher("播妞",999.9);ObjectFrame.save(s1);ObjectFrame.save(s2);}
}

最终结果是,将不同类的信息保存至文件中

3注解的使用

注解是和反射一起使用的,为了实现框架而服务。我们可以理解为JUnit这个注解一样,告诉系统加了这个注解就会执行,同样也和spring中定义bean的意思差不多,可以通过注解知道系统中有哪些bean。

  • Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序

3.1自定义注解的格式

public @interface MyTest{String aaa();boolean bbb() default true;	//default true 表示默认值为true,使用时可以不赋值。String[] ccc();
}

在这里阿插入图片描述
注意:注解的属性名如何是value的话,并且只有value没有默认值,使用注解时value名称可以省略。比如现在重新定义一个MyTest2注解

public @interface MyTest2{String value(); //特殊属性}
@MyTest2("孙悟空") //等价于 @MyTest2(value="孙悟空")

3.2注解本质是什么呢

1.MyTest1注解本质上是接口,每一个注解接口都继承子Annotation接口
2.MyTest1注解中的属性本质上是抽象方法
3.@MyTest1实际上是作为MyTest接口的实现类对象
4.@MyTest1(aaa=“孙悟空”,bbb=false,ccc={“Python”,“前端”,“Java”})里面的属性值,可以通过调用aaa()、bbb()、ccc()方法获取到

3.3元注解

元注解是修饰注解的注解

@Target是用来声明注解只能用在那些位置,比如:类上、方法上、成员变量上等
@Retetion是用来声明注解保留周期,比如:源代码时期、字节码时期、运行时期

在这里插入图片描述
例如test的@target就是type,@retention就是Runtime

3.4 解析注解

1.如果注解在类上,先获取类的字节码对象,再获取类上的注解
2.如果注解在方法上,先获取方法对象,再获取方法上的注解
3.如果注解在成员变量上,先获取成员变量对象,再获取变量上的注解
总之:注解在谁身上,就先获取谁,再用谁获取谁身上的注解
public class AnnotationTest3{@Testpublic void parseClass(){//1.先获取Class对象Class c = Demo.class;//2.解析Demo类上的注解if(c.isAnnotationPresent(MyTest4.class)){//获取类上的MyTest4注解MyTest4 myTest4 = (MyTest4)c.getDeclaredAnnotation(MyTest4.class);//获取MyTests4注解的属性值System.out.println(myTest4.value());System.out.println(myTest4.aaa());System.out.println(myTest4.bbb());}}@Testpublic void parseMethods(){//1.先获取Class对象Class c = Demo.class;//2.解析Demo类中test1方法上的注解MyTest4注解Method m = c.getDeclaredMethod("test1");if(m.isAnnotationPresent(MyTest4.class)){//获取方法上的MyTest4注解MyTest4 myTest4 = (MyTest4)m.getDeclaredAnnotation(MyTest4.class);//获取MyTests4注解的属性值System.out.println(myTest4.value());System.out.println(myTest4.aaa());System.out.println(myTest4.bbb());}}
}

上图为获取类和方法上的注解。

3.4 注解的应用场景-模拟Junit写一个测试框架

也就是将有注解的方法或者类进行特殊处理

public class AnnotationTest4{@MyTestpublic void test1(){System.out.println("=====test1====");}@MyTestpublic void test2(){System.out.println("=====test2====");}public void test3(){System.out.println("=====test2====");}public static void main(String[] args){AnnotationTest4 a = new AnnotationTest4();//1.先获取Class对象Class c = AnnotationTest4.class;//2.解析AnnotationTest4类中所有的方法对象Method[] methods = c.getDeclaredMethods();for(Method m: methods){//3.判断方法上是否有MyTest注解,有就执行该方法if(m.isAnnotationPresent(MyTest.class)){m.invoke(a);}}}
}

4.动态代理

关键点:接口(申明代理的方法,相当于把要做的抽象出来,可以在proxy产生代理对象的时候作为参数2表示代理的样子是什么样子)、工具类生成动态代理对象、Proxy类中的newInstamce产生代理对象、重写invoke方法可以实现回调函数

ProxyUtil工具类,为BigStar对象生成代理对象public class ProxyUtil {public static Star createProxy(BigStar bigStar){/* newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)参数1:用于指定一个类加载器参数2:指定生成的代理长什么样子,也就是有哪些方法参数3:用来指定生成的代理对象要干什么事情*/// Star starProxy = ProxyUtil.createProxy(s);// starProxy.sing("好日子") starProxy.dance()Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{Star.class}, new InvocationHandler() {@Override // 回调方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 代理对象要做的事情,会在这里写代码if(method.getName().equals("sing")){System.out.println("准备话筒,收钱20万");}else if(method.getName().equals("dance")){System.out.println("准备场地,收钱1000万");}return method.invoke(bigStar, args);}});return starProxy;}
}

new proxyInstance(loader,class<?> [] interfaces,invocationhalder):

  • 1、定义类加载器
  • 2、定义代理对象中应该有的方法,可以有多个接口
  • 3、这个是定义代理对象应该做什么

在这里插入图片描述

public class ProxyUtil {public static UserService createProxy(UserService userService){UserService userServiceProxy= (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),new Class[]{UserService.class}, new InvocationHandler() {@Overridepublic Object invoke(                                                                             Object proxy, Method method, Object[] args) throws Throwable {                             if(method.getName().equals("login") ||                                             method.getName().equals("deleteUsers")||method.getName().equals("selectUsers")){//方法运行前记录毫秒值         long startTime = System.currentTimeMillis();//执行方法Object rs = method.invoke(userService, args);//执行方法后记录毫秒值long endTime = System.currentTimeMillis();System.out.println(method.getName() + "方法执行耗时:" + (endTime - startTime)/ 1000.0 + "s");return rs;}else {Object rs = method.invoke(userService, args);return rs;                                                                }}                                                                 });//返回代理对象return userServiceProxy;}
}

AOP的底层也是动态代理实现,别的地方使用到的是mybatis中的延迟加载就是使用CGLIB动态代理,来实现需要用到这个函数时,采取执行搜索保存操作。

相关文章:

  • 常见面试题-TCP三次握手四次挥手
  • MySQL 是怎样运行的:单表访问方法及基于成本的优化
  • Windows 同步时间服务器批处理
  • 软件测试常见面试题1000问涵盖一千+公司面试软件测试面试题(全网最全)
  • 安全防御——二、ENSP防火墙实验学习
  • Ecal基于wifi下跨机通讯
  • 服务器的操作系统,你选择哪些?
  • 家政预约服务小程序源码系统 线上+线下两种模式 带完整的搭建教程
  • 运动想象 EEG 信号分析
  • 1.OpenResty系列之入门简介
  • JDBC SQL Server Source Connector: 一览与实践
  • MuLogin浏览器如何在一台设备上安全登录和管理多个LinkedIn账户?
  • 基于人工兔算法的无人机航迹规划-附代码
  • 成功解决fatal error: stdatomic.h: No such file or directory #include <stdatomic.h>
  • kmp算法详解+next数组求解
  • Angular数据绑定机制
  • Codepen 每日精选(2018-3-25)
  • css系列之关于字体的事
  • Debian下无root权限使用Python访问Oracle
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • Java到底能干嘛?
  • JAVA多线程机制解析-volatilesynchronized
  • Java教程_软件开发基础
  • jquery ajax学习笔记
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • RxJS: 简单入门
  • select2 取值 遍历 设置默认值
  • Vim 折腾记
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • Web标准制定过程
  • 测试如何在敏捷团队中工作?
  • 好的网址,关于.net 4.0 ,vs 2010
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 理解在java “”i=i++;”所发生的事情
  • 深入 Nginx 之配置篇
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 协程
  • 用Python写一份独特的元宵节祝福
  • 原生JS动态加载JS、CSS文件及代码脚本
  • HanLP分词命名实体提取详解
  • Java数据解析之JSON
  • 阿里云ACE认证之理解CDN技术
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • #162 (Div. 2)
  • (02)Hive SQL编译成MapReduce任务的过程
  • (26)4.7 字符函数和字符串函数
  • (6)STL算法之转换
  • (ZT)一个美国文科博士的YardLife
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (第27天)Oracle 数据泵转换分区表
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307