反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
1、反射第一步:加载类,获取类的字节码:Class对象
获取Class对象的三种方式:
1.直接使用类名.class获取:Class c1 = 类名.class
2.调用Class提供的方法:Class c2 = Class.forName("全类名")
3.调用Object提供的方法:Class c3 = 对象.getClass()
2.获取类的构造器
类中获取构造器的方法:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
获取构造器[下面是Class的方法]
Constructor<?>[] getConstructors() 获取所有的公共构造器(只能获取public修饰的)
Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到)
Constructor<T> getConstructor(Class<?>... parameterTypes) 获取某个公共构造器(只能获取public修饰的)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取某个构造器(只要存在就能拿到)
使用构造器(创建对象)[下面是Constructor的方法]
T newInstance(Object... initArgs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
注意
使如果想使用private修饰构造器反射创建对象,需要暴力反射(禁止JVM检查构造方法的访问权限)
*/
public class Demo2 {
public static void main(String[] args)
throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<Cat> catClass = Cat.class;
// Constructor<?>[] getConstructors() 获取所有的公共构造器(只能获取public修饰的)
Constructor<?>[] constructors = catClass.getConstructors();
System.out.println(constructors.length);
// Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到)
Constructor<?>[] declaredConstructors = catClass.getDeclaredConstructors();
System.out.println(declaredConstructors.length);
// Constructor<T> getConstructor(Class<?>... parameterTypes) 获取某个公共构造器(只能获取public修饰的)
Constructor<Cat> constructor = catClass.getConstructor();//获取无参构造器
System.out.println(constructor.getParameterAnnotations());
System.out.println("===========");
// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取某个构造器(只要存在就能拿到)
Constructor<Cat> declaredConstructor = catClass.getDeclaredConstructor(String.class,int.class);
System.out.println(declaredConstructor.getParameterCount());//获取参数计数
//使用构造器创建对象
Cat cat = constructor.newInstance();
System.out.println(cat);
//暴力破解
declaredConstructor.setAccessible(true);
Cat cat1 = declaredConstructor.newInstance("鸡鸡",1);
System.out.println(cat1);
}
}
从类中获取构造器的方法:
获取类构造器的作用:初始化对象返回:
运行结果:
3.获取类的成员变量
从类中获取成员变量的方法:
获取到成员变量的作用
操作实例:
import java.lang.reflect.Field;
/*
获取成员变量[Class提供]
public Field[] getFields() 获取类的所有公共成员变量(只能获取public修饰的)
public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到)
public Field getField(String name) 获取类的某个公共成员变量(只能获取public修饰的)
public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)
使用成员变量(赋值和取值) [Field提供]
public void set(Object obj, Object value): 赋值
public Object get(Object obj): 取值
public void setAccessible(boolean flag): 设置为true,表示禁止检查访问控制(暴力反射)
注意
使如果想使用private修饰的变量,需要暴力反射
*/
public class Demo3 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class<Cat> catClass = Cat.class;
Field[] declaredFields = catClass.getDeclaredFields();
System.out.println("变量个数"+declaredFields.length);
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName()+"-"+declaredField.getType());
}
Field a = catClass.getDeclaredField("a");
System.out.println(a.getName()+"-"+a.getType());
System.out.println("=======");
Cat cat = new Cat();
System.out.println(cat);
int a1 = (int)a.get(cat);
System.out.println(a1);
}
}
4.获取类的成员方法
从类中获取成员方法的API:
成员方法的使用:
package com.itheima.b_反射;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
获取成员方法[Class提供]
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,表示禁止检查访问控制(暴力反射)
注意
使如果想使用private修饰的成员方法,需要暴力反射
*/
public class Demo4 {
public static void main(String[] args)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<Cat> catClass = Cat.class;
//获取类的全部成员方法
Method[] declaredMethods = catClass.getDeclaredMethods();
System.out.println(declaredMethods.length);
for (Method declaredMethod : declaredMethods) {
System.out.println("方法名为"+declaredMethod.getName()+",返回类型为"+declaredMethod.getReturnType());
}
System.out.println("======");
//获取某个类的成员方法
Method method = catClass.getDeclaredMethod("eat",String.class);
System.out.println(method.getReturnType());
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
//触发某个对象的该方法执行
Cat cat = new Cat();
method.setAccessible(true);
String str = (String)method.invoke(cat, "小鱼");
System.out.println(str);
}
}
3.反射的作用:
1.可以在运行时得到一个类的全部成分然后操作
2.可以破坏封装性,也可以破坏泛型的约束性,更重要的用途是适合:做Java高级框架
3.基本上主流框架都会基于反射设计一些通用技术功能
单元测试
单元测试:就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。
Junit单元测试框架
可以用来对方法进行测试,它是由Junit公司开源出来的
优点:可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。 不需要程序员去分析测试的结果,会自动生成测试报告出来。
1.Junit框架快速入门:
为StringUtil创建一个测试类:
测试类中的测试方法一般取名为原方法+test
在方法上必须加上@Test
断言
断言是一种非常重要的功能,它用于验证测试中的一些条件是否为真。如果条件为真,那么测试通过;如果条件为假,那么测试失败。
常见断言assertEquals([String message],expected,actual):验证预期结果与实际结果是否相等。assertNotEquals([String message],expected,actual):验证预期结果与实际结果是否不相等。
参数说明:message(可选):将会在发生错误时报告这个消息。
expected(必填):期望值,通常都是用户指定的内容。
actual(必填):是被测试的代码返回的实际值。
运行结果:
2.Junit框架的常见注解
Junit单元测试框架的常用注解(Junit 4.xxxx版本)
在测试方法执行前执行的方法,常用于:初始化资源。
在测试方法执行完后再执行的方法,常用于:释放资源。
Junit单元测试框架的常用注解(Junit 5.xxxx版本)
这里我们以Junit-4.9版本为例