一.单元测试
1.1 什么是单元测试
1.2 目前测试方法是怎么进行的
1.3 Junit
1.Junit概述
JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单元测试。
此外,几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,JUnit目前最新版本是5。
- JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。
- Junit可以生成全部方法的测试报告。
- 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
1.4 单元测试快速入门
步骤
- 将Junit的jar包导入到项目中。
- 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。
- 在测试方法上使用@Test注解:标注该方法是一个测试方法
- 在测试方法中完成被测试方法的预期正确性测试。
- 选中测试方法,选择“JUnit运行” ,如果测试良好则是绿色;如果测试失败,则是红色
1.5 Junit常用注解
Junit常用注解(Junit 4.xxxx版本):
Junit常用注解(Junit 5.xxxx版本):
1.6 代码实例
二.反射(重要)
2.1 反射概述
反射是指对于任何Class类,在运行的时候,可以获取类的字节码文件对象,然后可以解析类中的全部成分。
- 在运行时,可以直接得到这个类的构造器对象:Construtor。
- 在运行时,可以直接得到这个类的成员变量对象:Field。
- 在运行时,可以直接得到这个类的成员方法对象:Method。
这种运行时动态获取类信息以及动态调用类中成分的能力称为反射。
2.2 反射的关键
反射的第一步都是先得到编译后的Class文件对象,然后就可以得到Class的全部成分。
2.3 反射获取类对象
反射的第一步就是获取Class类的对象,共有三种方式。
- 方式一:使用Class类中的静态方法forName,装入类,并做类的静态初始化,返回Class的对象代码格式如下:Class c1 = Class.forName("全类名");//全类名就是src下的全包名
- 方式二:JVM将使用类装载器,将类装入内存 (前提是:类还没有装入内存),不做类的初始化工作,返回Class的对象,代码格式如下: Class c2 = 类名.Class;
- 方式三:使用Object类中的getClass方法获取,会对类进行静态初始化,代码格式如下: Class c3 = 对象.getClass();
2.4 反射获取构造器对象
步骤:
- 首先得到类对象
- 通过类对象获取构造器对象
- 使用构造器对象创建类的对象
Class类中用于获取构造器的方法:
Constructor类中用于创建对象的方法:
作用
获取构造器的作用依然是获取一个对象并返回。
注意事项
如果某个构造器是私有的,那么需要打开权限(暴力反射),然后再创建对象。
范例
public class TestDemo {
//目标:掌握如何获取构造器对象,并利用构造器对象创建对象
//获取所有公共的构造器对象
@Test
public void getConstructors(){
//1.获得类对象
Class class1 = Student.class;
//2.获得所有公共构造器对象
Constructor[] constructors = class1.getConstructors();
//3.遍历构造器数组
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"===>"+constructor.getParameterCount());
}
}
//获取所有的构造器对象,无论构造器是公开的,还是私有的
@Test
public void getDeclaredConstructors(){
//1.获取类对象
Class class2 = Student.class;
//2.获取所有构造器对象
Constructor[] allConstructor = class2.getDeclaredConstructors();
//3.遍历构造器对象
for (Constructor constructor : allConstructor) {
System.out.println(constructor.getName()+"===>"+constructor.getParameterCount());
}
}
//获取单个构造器对象
@Test
public void getConstructor() throws Exception{
//1.获取类对象
Class class3 = Student.class;
//2.获取单个构造器
Constructor constructor = class3.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
//3.通过这个构造器创建对象
Student s = (Student) constructor.newInstance("张三",12);
System.out.println(s);
}
//获取单个构造器对象,无视构造器的访问权限
@Test
public void getDeclaredConstructor() throws Exception{
//1.获取类对象
Class class3 = Student.class;
//2.获取单个构造器
Constructor constructor = class3.getDeclaredConstructor();
//3.暴力反射
constructor.setAccessible(true);
//4.通过这个构造器创建对象
Student student = (Student) constructor.newInstance();
System.out.println(student);
}
}
2.5 反射获取成员变量对象
步骤:
- 首先得到类对象
- 从类对象中获取成员变量对象
Class类中用于获取成员变量的方法:
Field中用于取值、赋值的方法
作用
依然是为某个对象中对应的成员变量取值和赋值。
注意事项
如果某个成员变量是私有的,那么需要打开权限(暴力反射),然后再取值、赋值。
代码示例
public class FieldDemo1 {
//目标:掌握成员变量对象的获取,并对某个对象中相应的成员变量进行取值和赋值
//通过反射获取所有成员变量对象
@Test
public void getFields() throws Exception {
//1.获取类对象
Class class1 = Student.class;
//2.获取所有成员变量对象
Field[] fields = class1.getDeclaredFields();
//3.遍历所有成员变量对象
for (Field field : fields) {
System.out.println(field.getName()+"===>"+field.getType());
}
}
//通过反射获取一个成员变量并赋值
@Test
public void getField() throws Exception {
//1.获取类对象
Class class1 = Student.class;
//2.获取成员变量对象
Field name = class1.getDeclaredField("name");
//3.暴力反射
name.setAccessible(true);
//4.对成员变量赋值
Student s = new Student();
name.set(s,"张三");
//5.打印对象
System.out.println(s);
}
//通过反射获取一个成员变量并取值
@Test
public void getField2() throws Exception {
//1.获取类对象
Class class1 = Student.class;
//2.获取成员变量对象
Field name = class1.getDeclaredField("name");
//3.暴力反射
name.setAccessible(true);
//4.对成员变量取值
Student s = new Student("李四",12);
String s1 = (String) name.get(s);
//5.打印成员变量
System.out.println(s1);
}
}
2.6 反射获取成员方法对象
步骤:
- 首先获取类对象
- 通过类对象获取Method对象
- 运行方法
Class类中用于获取成员方法的方法:
Method类中用于触发执行的方法:
作用
获取成员方法的作用依然是在某个对象中执行此方法
注意事项
如果某个成员方法是私有的,那么需要打开权限(暴力反射),然后再执行此方法。
2.6 反射的作用——绕过编译阶段为集合添加数据
反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时可以为集合存入其他任意类型的元素。
1.原因
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
2.代码示例
2.7 反射的作用——通用框架的底层原理
1.需求: 给你任意一个对象,在不清楚对象字段的情况可以把对象的字段名称和对应值存储到文件中去。
2.代码示例
//框架代码:
public class MyBatisUtils {
public static void save(Object o){
try (
PrintStream ps = new PrintStream(new FileOutputStream("junit-reflect-annotation-proxy/src/reflect.txt",true))
){
//1.得到类对象
Class aClass = o.getClass();
ps.println("================="+aClass.getSimpleName()+"=================");
//2.得到类中全部的成员变量对象
Field[] fields = aClass.getDeclaredFields();
//3.得到全部成员变量对象的名字和值
for (Field field : fields) {
field.setAccessible(true);
String name = field.getName();
String value = field.get(o)+" ";
//4.保存到文件中
ps.println(name+"---"+value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//测试代码:
public class ReflectDemo1 {
public static void main(String[] args) {
//目标:利用反射技术,做一个通用框架
//向对象中添加数据,并将对象传到框架中
Student s = new Student("张三",17,'男',12,"3000");
MyBatisUtils.save(s);
Tercher t = new Tercher("张三",17,'男',"王标");
MyBatisUtils.save(t);
}
}