目录
1.单元测试
1.1单元测试概述
总结:
1.2单元测试快速入门
总结:
1.3单元测试常用注解
总结:
2.反射
2.1反射概述
总结:
2.2反射获取类对象
总结:
2.3反射获取构造器对象
总结:
2.4反射获取成员变量对象
总结:
2.5反射获取方法对象
总结:
总结:
2.7反射的作用-通用框架的底层原理
案例:反射做通用框架
总结:
单元测试
单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性。
前测试方法是怎么进行的,存在什么问题
只有一个main方法,如果一个方法的测试失败了,其他方法测试会受到影响。
无法得到测试的结果报告,需要程序员自己去观察测试是否成功。
无法实现自动化测试。
Junit单元测试框架
JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单元测试。
此外,几乎所有的IDE工具都集成了JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,JUnit目前最新版本是5。
JUnit优点
JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。
Junit可以生成全部方法的测试报告。
单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
Junit单元测试是做什么的?
测试类中方法的正确性的。
Junit单元测试的优点是什么?
JUnit可以选择执行哪些测试方法,可以一键执行全部测试方法的测试。
JUnit可以生测试报告,如果测试良好则是绿色;如果测试失败,则是红色。
单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
案例:单元测试快速入门
需求:使用单元测试进行业务方法预期结果、正确性测试的快速入门
分析:
1.将JUnit的jar包导入到项目中
2.编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。
3.在测试方法上使用@Test注解:标注该方法是一个测试方法
4.在测试方法中完成被测试方法的预期正确性测试。
5.选中测试方法,选择“JUnit运行” ,如果测试良好则是绿色;如果测试失败,则是红色
/**
业务方法
*/
public class UserService {
public String loginName(String loginName , String passWord){
if("admin".equals(loginName) && "123456".equals(passWord)){
return "登录成功";
}else {
return "用户名或者密码有问题";
}
}
public void selectNames(){
System.out.println(10/2);
System.out.println("查询全部用户名称成功~~");
}
}
import org.junit.*;
/**
测试类
*/
public class TestUserService {
// 修饰实例方法的
@Before
public void before(){
System.out.println("===before方法执行一次===");
}
@After
public void after(){
System.out.println("===after方法执行一次===");
}
// 修饰静态方法
@BeforeClass
public static void beforeClass(){
System.out.println("===beforeClass方法执行一次===");
}
@AfterClass
public static void afterClass(){
System.out.println("===afterClass方法执行一次===");
}
/**
测试方法
注意点:
1、必须是公开的,无参数 无返回值的方法
2、测试方法必须使用@Test注解标记。
*/
@Test
public void testLoginName(){
UserService userService = new UserService();
String rs = userService.loginName("admin","123456");
// 进行预期结果的正确性测试:断言。
Assert.assertEquals("您的登录业务可能出现问题", "登录成功", rs );
}
@Test
public void testSelectNames(){
UserService userService = new UserService();
userService.selectNames();
}
}
JUnit单元测试的实现过程是什么样的?
必须导入Junit框架的jar包。
定义的测试方法必须是无参数无返回值,且公开的方法。
测试方法使用@Test注解标记。
JUnit测试某个方法,测试全部方法怎么处理?成功的标志是什么?
测试某个方法直接右键该方法启动测试。
测试全部方法,可以选择类或者模块启动。
红色失败,绿色通过。
Junit常用注解(Junit 4.xxxx版本)
开始执行的方法:初始化资源。
执行完之后的方法:释放资源。
Junit常用注解(Junit 5.xxxx版本)
开始执行的方法:初始化资源。
执行完之后的方法:释放资源。
JUnit4的注解有哪些?
反射概述
反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:Constructor
在运行时,可以直接得到这个类的成员变量对象:Field
在运行时,可以直接得到这个类的成员方法对象:Method
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。
反射的关键:
反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。
反射的基本作用、关键?
反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分
反射的核心思想和关键就是:得到编译以后的class文件对象。
/**
目标:反射的第一步:获取Class对象
*/
public class Test {
public static void main(String[] args) throws Exception {
// 1、Class类中的一个静态方法:forName(全限名:包名 + 类名)
Class c = Class.forName("com.itheima.d2_reflect_class.Student");
System.out.println(c); // Student.class
// 2、类名.class
Class c1 = Student.class;
System.out.println(c1);
// 3、对象.getClass() 获取对象对应类的Class对象。
Student s = new Student();
Class c2 = s.getClass();
System.out.println(c2);
}
}
public class Student {
}
反射的第一步是什么?
获取Class类对象,如此才可以解析类的全部成分
获取Class类的对象的三种方式
方式一:Class c1 = Class.forName(“全类名”);
方式二:Class c2 = 类名.class
方式三:Class c3 = 对象.getClass();
使用反射技术获取构造器对象并使用
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取构造器的方法
获取构造器的作用依然是初始化一个对象返回。
Constructor类中用于创建对象的方法
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
目标:反射_获取Constructor构造器对象.
反射的第一步是先得到Class类对象。(Class文件)
反射中Class类型获取构造器提供了很多的API:
1. Constructor getConstructor(Class... parameterTypes)
根据参数匹配获取某个构造器,只能拿public修饰的构造器,几乎不用!
2. Constructor getDeclaredConstructor(Class... parameterTypes)
根据参数匹配获取某个构造器,只要申明就可以定位,不关心权限修饰符,建议使用!
3. Constructor[] getConstructors()
获取所有的构造器,只能拿public修饰的构造器。几乎不用!!太弱了!
4. Constructor[] getDeclaredConstructors()
获取所有申明的构造器,只要你写我就能拿到,无所谓权限。建议使用!!
小结:
获取类的全部构造器对象: Constructor[] getDeclaredConstructors()
-- 获取所有申明的构造器,只要你写我就能拿到,无所谓权限。建议使用!!
获取类的某个构造器对象:Constructor getDeclaredConstructor(Class... parameterTypes)
-- 根据参数匹配获取某个构造器,只要申明就可以定位,不关心权限修饰符,建议使用!
*/
public class TestStudent01 {
// 1. getConstructors:
// 获取全部的构造器:只能获取public修饰的构造器。
// Constructor[] getConstructors()
@Test
public void getConstructors(){
// a.第一步:获取类对象
Class c = Student.class;
// b.提取类中的全部的构造器对象(这里只能拿public修饰)
Constructor[] constructors = c.getConstructors();
// c.遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
// 2.getDeclaredConstructors():
// 获取全部的构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。
@Test
public void getDeclaredConstructors(){
// a.第一步:获取类对象
Class c = Student.class;
// b.提取类中的全部的构造器对象
Constructor[] constructors = c.getDeclaredConstructors();
// c.遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
// 3.getConstructor(Class... parameterTypes)
// 获取某个构造器:只能拿public修饰的某个构造器
@Test
public void getConstructor() throws Exception {
// a.第一步:获取类对象
Class c = Student.class;
// b.定位单个构造器对象 (按照参数定位无参数构造器 只能拿public修饰的某个构造器)
Constructor cons = c.getConstructor();
System.out.println(cons.getName() + "===>" + cons.getParameterCount());
}
// 4.getConstructor(Class... parameterTypes)
// 获取某个构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。
@Test
public void getDeclaredConstructor() throws Exception {
// a.第一步:获取类对象
Class c = Student.class;
// b.定位单个构造器对象 (按照参数定位无参数构造器)
Constructor cons = c.getDeclaredConstructor();
System.out.println(cons.getName() + "===>" + cons.getParameterCount());
// c.定位某个有参构造器
Constructor cons1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());
}
}
import org.junit.Test;
import java.lang.reflect.Constructor;
/**
目标: 反射_获取Constructor构造器然后通过这个构造器初始化对象。
反射获取Class中的构造器对象Constructor作用:
也是初始化并得到类的一个对象返回。
Constructor的API:
1. T newInstance(Object... initargs)
创建对象,注入构造器需要的数据。
2. void setAccessible(true)
修改访问权限,true代表暴力攻破权限,false表示保留不可访问权限(暴力反射)
小结:
可以通过定位类的构造器对象。
如果构造器对象没有访问权限可以通过:void setAccessible(true)打开权限
构造器可以通过T newInstance(Object... initargs)调用自己,传入参数!
*/
public class TestStudent02 {
// 1.调用构造器得到一个类的对象返回。
@Test
public void getDeclaredConstructor() throws Exception {
// a.第一步:获取类对象
Class c = Student.class;
// b.定位单个构造器对象 (按照参数定位无参数构造器)
Constructor cons = c.getDeclaredConstructor();
System.out.println(cons.getName() + "===>" + cons.getParameterCount());
// 如果遇到了私有的构造器,可以暴力反射
cons.setAccessible(true); // 权限被打开
Student s = (Student) cons.newInstance();
System.out.println(s);
System.out.println("-------------------");
// c.定位某个有参构造器
Constructor cons1 = c.getDeclaredConstructor(String.class, int.class);
System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());
Student s1 = (Student) cons1.newInstance("孙悟空", 1000);
System.out.println(s1);
}
}
public class Student {
private String name;
private int age;
private Student(){
System.out.println("无参数构造器执行!");
}
public Student(String name, int age) {
System.out.println("有参数构造器执行!");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
利用反射技术获取构造器对象的方式
getDeclaredConstructors()
getDeclaredConstructor (Class>... parameterTypes)
反射得到的构造器可以做什么?
依然是创建对象的:
public newInstance(Object... initargs)
如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象
setAccessible(boolean)
反射可以破坏封装性,私有的也可以执行了。
使用反射技术获取成员变量对象并使用
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取成员变量的方法
获取成员变量的作用依然是在某个对象中取值、赋值
Field类中用于取值、赋值的方法
import org.junit.Test;
import java.io.File;
import java.lang.reflect.Field;
/**
目标:反射_获取Field成员变量对象。
反射的第一步是先得到Class类对象。
1、Field getField(String name);
根据成员变量名获得对应Field对象,只能获得public修饰
2.Field getDeclaredField(String name);
根据成员变量名获得对应Field对象,只要申明了就可以得到
3.Field[] getFields();
获得所有的成员变量对应的Field对象,只能获得public的
4.Field[] getDeclaredFields();
获得所有的成员变量对应的Field对象,只要申明了就可以得到
小结:
获取全部成员变量:getDeclaredFields
获取某个成员变量:getDeclaredField
*/
public class FieldDemo01 {
/**
* 1.获取全部的成员变量。
* Field[] getDeclaredFields();
* 获得所有的成员变量对应的Field对象,只要申明了就可以得到
*/
@Test
public void getDeclaredFields(){
// a.定位Class对象
Class c = Student.class;
// b.定位全部成员变量
Field[] fields = c.getDeclaredFields();
// c.遍历一下
for (Field field : fields) {
System.out.println(field.getName() + "==>" + field.getType());
}
}
/**
2.获取某个成员变量对象 Field getDeclaredField(String name);
*/
@Test
public void getDeclaredField() throws Exception {
// a.定位Class对象
Class c = Student.class;
// b.根据名称定位某个成员变量
Field f = c.getDeclaredField("age");
System.out.println(f.getName() +"===>" + f.getType());
}
}
import org.junit.Test;
import java.lang.reflect.Field;
/**
目标:反射获取成员变量: 取值和赋值。
Field的方法:给成员变量赋值和取值
void set(Object obj, Object value):给对象注入某个成员变量数据
Object get(Object obj):获取对象的成员变量的值。
void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。
Class getType(); 获取属性的类型,返回Class对象。
String getName(); 获取属性的名称。
*/
public class FieldDemo02 {
@Test
public void setField() throws Exception {
// a.反射第一步,获取类对象
Class c = Student.class;
// b.提取某个成员变量
Field ageF = c.getDeclaredField("age");
ageF.setAccessible(true); // 暴力打开权限
// c.赋值
Student s = new Student();
ageF.set(s , 18); // s.setAge(18);
System.out.println(s);
// d、取值
int age = (int) ageF.get(s);
System.out.println(age);
}
}
public class Student {
private String name;
private int age;
public static String schoolName;
public static final String COUNTTRY = "中国";
public Student(){
System.out.println("无参数构造器执行!");
}
public Student(String name, int age) {
System.out.println("有参数构造器执行!");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
利用反射技术获取成员变量的方式
获取类中成员变量对象的方法
getDeclaredFields()
getDeclaredField (String name)
反射得到成员变量可以做什么?
依然是在某个对象中取值和赋值。
void set(Object obj, Object value):
Object get(Object obj)
如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
setAccessible(boolean)
使用反射技术获取方法对象并使用
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取成员方法的方法
获取成员方法的作用依然是在某个对象中进行执行此方法
Method类中用于触发执行的方法
import org.junit.Test;
import java.lang.reflect.Method;
/**
目标:反射——获取Method方法对象
反射获取类的Method方法对象:
1、Method getMethod(String name,Class...args);
根据方法名和参数类型获得对应的方法对象,只能获得public的
2、Method getDeclaredMethod(String name,Class...args);
根据方法名和参数类型获得对应的方法对象,包括private的
3、Method[] getMethods();
获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
4、Method[] getDeclaredMethods();
获得类中的所有成员方法对象,返回数组,只获得本类申明的方法。
Method的方法执行:
Object invoke(Object obj, Object... args)
参数一:触发的是哪个对象的方法执行。
参数二: args:调用方法时传递的实际参数
*/
public class MethodDemo01 {
/**
* 1.获得类中的所有成员方法对象
*/
@Test
public void getDeclaredMethods(){
// a.获取类对象
Class c = Dog.class;
// b.提取全部方法;包括私有的
Method[] methods = c.getDeclaredMethods();
// c.遍历全部方法
for (Method method : methods) {
System.out.println(method.getName() +" 返回值类型:" + method.getReturnType() + " 参数个数:" + method.getParameterCount());
}
}
/**
* 2. 获取某个方法对象
*/
@Test
public void getDeclardMethod() throws Exception {
// a.获取类对象
Class c = Dog.class;
// b.提取单个方法对象
Method m = c.getDeclaredMethod("eat");
Method m2 = c.getDeclaredMethod("eat", String.class);
// 暴力打开权限了
m.setAccessible(true);
m2.setAccessible(true);
// c.触发方法的执行
Dog d = new Dog();
// 注意:方法如果是没有结果回来的,那么返回的是null.
Object result = m.invoke(d);
System.out.println(result);
Object result2 = m2.invoke(d, "骨头");
System.out.println(result2);
}
}
public class Dog {
private String name ;
public Dog(){
}
public Dog(String name) {
this.name = name;
}
public void run(){
System.out.println("狗跑的贼快~~");
}
private void eat(){
System.out.println("狗吃骨头");
}
private String eat(String name){
System.out.println("狗吃" + name);
return "吃的很开心!";
}
public static void inAddr(){
System.out.println("在黑马学习Java!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
利用反射技术获取成员方法对象的方式
获取类中成员方法对象
getDeclaredMethods()
getDeclaredMethod (String name, Class>... parameterTypes)
反射得到成员方法可以做什么?
依然是在某个对象中触发该方法执行。
Object invoke(Object obj, Object... args)
如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行
setAccessible(boolean)
2.6反射的作用-绕过编译阶段为集合添加数据
反射的作用-绕过编译阶段为集合添加数据
反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
import java.lang.reflect.Method;
import java.util.ArrayList;
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 需求:反射实现泛型擦除后,加入其他类型的元素
ArrayList lists1 = new ArrayList<>();
ArrayList lists2 = new ArrayList<>();
System.out.println(lists1.getClass());
System.out.println(lists2.getClass());
System.out.println(lists1.getClass() == lists2.getClass()); // ArrayList.class
System.out.println("---------------------------");
ArrayList lists3 = new ArrayList<>();
lists3.add(23);
lists3.add(22);
// lists3.add("黑马");
Class c = lists3.getClass(); // ArrayList.class ===> public boolean add(E e)
// 定位c类中的add方法
Method add = c.getDeclaredMethod("add", Object.class);
boolean rs = (boolean) add.invoke(lists3, "黑马");
System.out.println(rs);
System.out.println(lists3);
ArrayList list4 = lists3;
list4.add("白马");
list4.add(false);
System.out.println(lists3);
}
}
反射为何可以给约定了泛型的集合存入其他类型的元素?
编译成Class文件进入运行阶段的时候,泛型会自动擦除。
反射是作用在运行时的技术,此时已经不存在泛型了。
需求:给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。
需求:
给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。
分析:
定义一个方法,可以接收任意类的对象。
每次收到一个对象后,需要解析这个对象的全部成员变量名称。
这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
使用反射获取对象的Class类对象,然后获取全部成员变量信息。
遍历成员变量信息,然后提取本成员变量在对象中的具体值
存入成员变量名称和值到文件中去即可。
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class MybatisUtil {
/**
保存任意类型的对象
* @param obj
*/
public static void save(Object obj){
try (
PrintStream ps = new PrintStream(new FileOutputStream("F:\\BaiduNetdiskDownload\\junit-reflect-annotation-proxy-app\\src\\com\\itheima\\新建文本文档.txt", true));
){//
// 1、提取这个对象的全部成员变量:只有反射可以解决
Class c = obj.getClass(); // c.getSimpleName()获取当前类名 c.getName获取全限名:包名+类名
ps.println("================" + c.getSimpleName() + "================");
// 2、提取它的全部成员变量
Field[] fields = c.getDeclaredFields();
// 3、获取成员变量的信息
for (Field field : fields) {
String name = field.getName();
// 提取本成员变量在obj对象中的值(取值)
field.setAccessible(true);
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.util.Date;
import java.util.Properties;
/**
目标:提供一个通用框架,支持保存所有对象的具体信息。
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
Student s = new Student();
s.setName("猪八戒");
s.setClassName("西天跑路1班");
s.setAge(1000);
s.setHobby("吃,睡");
s.setSex('男');
MybatisUtil.save(s);
Teacher t = new Teacher();
t.setName("波仔");
t.setSex('男');
t.setSalary(6000);
MybatisUtil.save(t);
}
}
public class Student {
private String name;
private char sex;
private int age;
private String className;
private String hobby;
public Student(){
}
public Student(String name, char sex, int age, String className, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.className = className;
this.hobby = hobby;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
public class Teacher {
private String name;
private char sex;
private double salary;
public Teacher(){
}
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
反射的作用?
可以在运行时得到一个类的全部成分然后操作。
可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)
更重要的用途是适合:做Java高级框架
基本上主流框架都会基于反射设计一些通用技术功能。