第1章 Junit 单元测试
Junit 介绍为了对某个方法进行更快捷地测试,我们需要学习Junit 技术。
JUnit 是一个Java 语言的单元测试框架,简单理解为可以用于取代 java 的 main 方法。Junit 属于第三方工具,一般情况下需要导入 jar 包,不过,多数 Java 开发环境已经集成了JUnit 作为单元测试工具。
- Junit-入门案例
- 需求:快捷对以下run1 方法进行测试
- 实现步骤:
效果:
@Test 修饰的要求:必须 public、无 static、无参、无返回值
Junit-进阶案例凡是加入@符号的,Java 中我们都称为注解。常用注解
@Test, 修饰需要被执行的测试方法
@Before,修饰的方法无法独立执行,必须在 测试方法执行之前先执行@After, 修饰的方法无法独立执行,必须在 测试方法执行之后再执行被以上三个注解修饰的的方法:必须 public、无 static、无参、无返回值
public class JunitDemo_1 { @Test
public void myTest(){ System.out.println("测试 test");
}
@Before
public void myBefore(){ System.out.println("方法前");
}
@After
public void myAfter(){ System.out.println("方法后");
}
/*运行结果:
- 方法前
- 测试 test
- 方法后
*/
}
执行类中全部测试方法:
常见错误:
第2章 反射【重点】
学习前准备学习前准备---知识储备- 需要掌握 6 个单词
- Class 类
- Constructor 构造方法
- Method 方法
- Field 字段
- instance 实例
- invoke 执行引言
为了能够更加灵活地访问类中的所有内容(包含 private),我们就需要反射技术
通过反射技术,我们可以轻松访问图中类的 private 内容。
- 反射概述
反射:针对性地映射 某一个完整事物的行为或特征 (单独操作类中任意内容 的超能力)
Java 反射机制是在运行状态中:
- 对于任意一个类,都能够知道这个类的所有属性和方法(包含 private);
- 对于任意一个对象,都能够调用它的任意一个方法和属性(包含 private);这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
把类中任意部分作为对象获取到:
- 类:Class 对象
- 变量(字段):Field 对象
- 方法:Method 对象
- 构造方法:Constructor 对象反射入门案例-方法入门 1:强制执行 private 方法
学习访问权限时,我们就知道,private 修饰的方法,仅限当前类内部使用。
我们可以通过反射技术,在不修改访问权限修饰符的前提下,在外界使用 private 方法。
- 准备数据:
public class Person {
private void t1(){
System.out.println("私有的 t1 方法执行");
}
private void t2(){
System.out.println("私有的 t2 方法执行");
}
}
- 需求说明:
定义一个测试类,测试类中执行 Person 类中的 t1 方法。
- 分析:
因为Person 类中的 t1 方法是 private 修饰,正常创建对象方式无法调用方法。只能依靠反射技术
- 代码实现:
public static void main(String[] args) throws Exception {
//1、获取
//1.1、获取类对象
Class<?> clazz = Class.forName("com.czxy.demo2.d1.Person");
//1.2、获取类中方法
Method t1 = clazz.getDeclaredMethod("t1");
//1.3、(private)设置类外可用-暴力反射
t1.setAccessible(true);
//2、执行
//2.1、获取类中构造方法
Constructor<?> c = clazz.getConstructor();
//2.2、根据构造方法创建对象
Object person = c.newInstance();
//2.3、调用方法
t1.invoke(person);
}
- 技巧说明:
获取全类名的两种方式:
- 注意事项:
- 小结:
反射执行 private 方法步骤:
1、获取
- 、获取类对象
- 、获取类中方法
- 、(private)设置类外可用-暴力反射
2、执行
- 、获取类中构造方法
- 、根据构造方法创建对象
- 、调用方法
思考:
控制台输入方法名:t1 或 t2,输入的方法名是什么,就执行 Person 中的哪个方法。如果输入的方法不存在,展示“方法不存在”
- 入门 2:执行带参方法-private
- 准备数据:原有 Person 类加入 t3 方法
}
}
System.out.println("整数:" b);
public class Person {
private void t1(){
System.out.println("私有的 t1 方法执行");
}
private void t2(){
System.out.println("私有的 t2 方法执行");
}
private void t3(String a,int b){
System.out.println("字符串:" a);
- 需求说明:
定义一个测试类,测试类中执行Person 类中的 t3 方法,方法传入“传智” 1024
- 分析:
private 方法仍然是使用反射技术调用,但在获取方法和执行方法上要注意有方法参数
- 代码实现:
public static void main(String[] args) throws Exception {
//1、获取
//1.1、获取类对象
Class<?> clazz = Class.forName("com.czxy.demo2.d1.Person");
//1.2、获取类中方法(告诉程序,t3 方法有 String 和 int 两个参数)
Method t3 = clazz.getDeclaredMethod("t3", String.class, int.class);
//1.3、设置类外可用
t3.setAccessible(true);
//2、执行
//2.1、获取类中构造方法
Constructor<?> c = clazz.getConstructor();
//2.2、根据构造方法创建对象
Object person = c.newInstance();
//2.3、调用方法(分别为 String 和 int 赋值)
t3.invoke(person,"传智",1024);
}
- 注意事项:
- 小结:
反射执行带参方法,获取和执行时都要注意参数
- 入门 3:执行带返回值方法-private
- 准备数据:原有Person 类加入 t4 方法
public class Person {
private void t1(){
System.out.println("私有的 t1 方法执行");
}
private void t2(){
System.out.println("私有的 t2 方法执行");
}
private void t3(String a,int b){
System.out.println("字符串:" a);
System.out.println("整数:" b);
}
private String t4(){
return "t4 方法的返回值";
}
}
- 需求说明:
定义一个测试类,测试类中执行Person 类中的 t4 方法,展示方法返回值
- 分析:
private 方法仍然是使用反射技术调用,执行方法完毕,接收返回值即可
- 代码实现:
public static void main(String[] args) throws Exception {
//1、获取
//1.1、获取类对象
Class<?> clazz = Class.forName("com.czxy.demo2.d1.Person");
//1.2、获取类中方法
Method t3 = clazz.getDeclaredMethod("t4");
//1.3、设置类外可用
t3.setAccessible(true);
//2、执行
//2.1、获取类中构造方法
Constructor<?> c = clazz.getConstructor();
//2.2、根据构造方法创建对象
Object person = c.newInstance();
//2.3、调用方法(接收返回值)
Object x = t3.invoke(person);
String str = (String) x;
System.out.println(str);
}
- 小结:
反射调用方法的返回值是 Object 类型,可以通过强转 转为具体使用格式(强转前一定确定,方法返回值真正是什么类型,否则类型不匹配报异常)
- 入门总结
反射方式调用方法,可以让我们使用类中任何方法(包括 private) 格式:
反射执行 private 方法步骤:(即使 2.1 和 2.2 紧跟在 1.1 之后,也是一种编写方式)
1、获取
- 、获取类对象
- 、获取类中方法
- 、(private)设置类外可用-暴力反射
2、执行
- 、获取类中构造方法、根据构造方法创建对象、调用方法反射进阶案例进阶 1:执行 public 方法
- 准备代码:
public class Phone { public void start(){
System.out.println("开机");
}
}
- 反射代码:
@Test
public void run() throws Exception {
//1、获取类的 Class 对象
Class<?> clazz = Class.forName("cn.czxy.demo2.Phone");
//2 、 通 过 Constructor 实 例 化 对 象 Constructor<?> c1 = clazz.getConstructor(); Object obj = c1.newInstance();
//3、获取 Method 对象
Method m1 = clazz.getMethod("start");
//4、执行方法m1.invoke(obj);
}
- 小结:
1、
getMethod(); 获取当前类或父类中的 public 修饰的方法
getDeclaredMethod(); 获取当前类中任意的方法(无视访问权限)
2、若使用 getMethod();方法尝试获取非 public 修饰的方法,会出现如下异常:
3、反射 private 方法 必须使用 setAccessible(true),否则将抛异常:
- 测试代码:
@Test
public void run3() throws Exception{
//1、获取 Class 对象
Class<?> c1 = Class.forName("cn.czxy.demo5.People");
//2、通过构造方法创建对象(链式编程)
Object obj = c1.getConstructor().newInstance();
//3、获取 Field 对象
Field idNum = c1.getDeclaredField("idNum");
//设置该方法在外界暂时可用idNum.setAccessible(true);
//4、赋值/取值idNum.set(obj, "666666");
Object idNumStr = idNum.get(obj); System.out.println(idNumStr);
}
- 进阶 3:执行 public 字段
- 准备代码:
public class Person {
public String name="小智";
}
- 反射代码:
@Test
public void run1() throws Exception{
//1、获得 类的“Class 对象”
Class<?> clazz = Class.forName("cn.czxy.demo3.Person");
//2 、 通 过 Constructor 实 例 化 对 象 Constructor<?> c1 = clazz.getConstructor(); Object obj = c1.newInstance();
//3、获取 Field 对象
Field f1 = clazz.getField("name");
//4、赋值/取值
Object str = f1.get(obj); System.out.println(str); f1.set(obj, "小明");
}
注意:
1、getField(); 只能获取当前类或父类中 public 修饰的字段
getDeclaredField (); 获取当前类中的任意字段(无视访问权限修饰符)
2、若使用 getField ();方法尝试获取非 public 修饰的字段,会出现如下异常:
3、反射 private 字段 必须使用 setAccessible(true),否则将抛异常:
- 准备代码:
public class Person { private Person() {
System.out.println("私有无参构造");
}
}
- 测试代码:
@Test
public void run1() throws Exception{
//1、获取 Class 对象
Class<?> c1 = Class.forName("cn.czxy.demo5.Person");
//2 、 获 取 非 公 有 构 造 方 法 ( 不 是 public) Constructor<?> c = c1.getDeclaredConstructor();
//设置该构造方法在外界暂时可用
c.setAccessible(true);
//使用私有构造创建对象
Object obj = c.newInstance();
}
- 进阶 5:通过带参构造创建对象(public 修饰)
- 准备代码:
public class Phone {
//普通方法
public void call(String num){ System.out.println("打电话给:" num);
}
public String shutDown(){ return "关机成功";
}
//构造方法
public Phone() { System.out.println("Phone 无参构造");
}
public Phone(String a,int b) { System.out.println("Phone 带参构造" a b);
}
}
- 代码实现:
@Test
public void run5() throws Exception{
//1、获取 Class 对象
Class<?> clazz = Class.forName("cn.czxy.demo4.Phone");
//2、通过带参构造创建对象
Constructor<?> c = clazz.getConstructor(String.class,int.class);
Object obj = c.newInstance("你好",10);
}
1、getConstructor(); 只能获取当前类中,public 修饰的任意构造方法
getDeclaredConstructor(); 获取当前类中任何构造方法(无视访问权限修饰符)
2、若使用 getConstructor();方法尝试获取非 public 修饰的构造方法,会出现如下异常:
3、反射 private 构造方法 必须使用 setAccessible(true),否则将抛异常:
- 需求说明:获取某个类中所有的方法 & 所有的字段 &所有构造方法
getMethods(); 获取当前类及父类中所有的 public 修饰的方法
getDeclaredMethods(); 获取当前类中所有的方法(无视访问权限)
getFields(); 获取当前类及父类中所有的 public 修饰的字段
getDeclaredFields (); 获取当前类中的所有字段(无视访问权限修饰符)
getConstructors(); 获取当前类中所有的 public 修饰的构造方法
getDeclaredConstructors(); 获取当前类中所有构造方法(无视访问权限修饰符)
总结:
所有未加 Declared 的方法,都能获取当前类及父类所有 public 内容所有加 Declared 的方法,都能获取当前类所有内容
高级 2:获取类的 Class 对象的三种方式@Test
public void run1() throws Exception{
//1、通过 Class.forName()方法
Class c1 = Class.forName("cn.czxy.demo4.Phone");
//2、类名.class
Class c2 = Phone.class;
//3、对象名.getClass()方法Phone p1 = new Phone(); Class c3 = p1.getClass();
}
注意:以上三种方式获取的某个类的 Class 对象都是同一个
- 类加载顺序
任何 class 文件使用时,都会成为内存中的一个 Class 对象
- Class 对象 拥有这个类 所有内容(成员变量、成员方法、构造方法等等)
- 反射综合案例提高练习:使用对象私有成员
- 准备代码:Person.java
public class Person {
//家里的小金库
private double deposit;
//从家里小金库里取出 1 千
private double withDraw(){ double money = 1000.0;
// 尝 试 取 1000 deposit-=money; if(deposit<0){
//若小金库不足 1000,无法取出deposit =money;
return 0.0;
}
return money;
}
}
- 准备代码:测试类
@Test
public void run1() throws Exception{ Person p1 = new Person();
//请补全代码,完成以下操作
//1、为对象 p1 的成员变量 deposit 赋值 20 万
//2、使用对象 p1 的 withDraw()方法,取出 5000
}
要求:
1、 Person.java 的源代码不可改变
2、 补全代码:为对象 p1 的成员变量 deposit 赋值 20 万
3、 补全代码:使用对象 p1 的 withDraw()方法,取出 5000
提示:
Person 对象 p1 已经存在,就无需反射构造方法创建对象了, 直接使用 p1 对象即可
综合练习:寻找某些指定方法执行【扩展,仅供学有余力同学自学】- 准备代码:DemoTest.java
public class DemoTest {
public void run1(){System.out.println("run1");} void run2(){System.out.println("run2");}
private void run3(){System.out.println("run3");}
void test1(){System.out.println("test1");} void test2(){System.out.println("test2");}
public void test3(){System.out.println("test3");}
protected void run1es(){System.out.println("run1es");} void run2es(){System.out.println("run2es");}
private void run3es(){System.out.println("run3es");}
}
要求:
1、执行所有以“run”开头的方法。(方法无参、无返回值)
2、执行以“es”结尾的方法,要求方法必须以 public 修饰。(方法无参、无返回值)
若找不到,则展示“没有 es 结尾的方法”
提示:
1、获取方法的名字: method 对象.getName(); 2、获取多个 method 的方法: