一、Junit测试
1.Junit 主要用于单元测试 也就是局部测试 可以通过局部单元测试 查找代码出现bug
2.测试
黑盒测试 功能测试 接口测试 不需要编写代码 瞎点 根据测试用例进行测试
白盒测试 性能测试 编写脚本代码 shell脚本 语法与指令(测试)
3.Junit 单元测试
4.使用的步骤
需要进行导包 junit jar
定义一个类
定义方法 在方法上加上@Test 注解
访问修饰符public
没有返回值 只能使用void J进行修饰
其余跟普通方法一样
5.操作流程
step01 新建一个文件 lib 目录 用于存放jar
step2 将jar添加项目依赖
public class Test {
// @org.junit.Test
@org.junit.Test
public void show(){
// System.out.println("我是局部测试");
System.out.println(1/0);
}
}
二、反射的概念
1.反射是所有框架的灵魂 所有的框架都需要用到反射 所有的类在反射面前都是裸体(私有的 公有)
2.框架 :半成品 在半成品的基础进行开发 效率会更高 大部分公司提倡使用框架
市场分布式解决方案
1.ssm+doubb(阿里) spring +spring mvc +mybatis +doubb
2.spring cloud +spring boot (趋势)
3.反射机制:将类的各个组成部分 分装成其他的对象(Class对象)就是反射机制
注意:Class阶段会先执行静态代码
三、反射-获取Class对象
1.第一种方式:通过实例化一个对象 对象在调用 getClass() 方法来获取 (很少使用这种方式)
2.第二种方式:直接通过类名.class来获取
3.第三种方式:通过 Class.forName(“完整的包名+类名”); (最多使用)
4.代码
第三种方式 只要完整的包名加类名 无需项目名
如果你只是希望一个类的静态代码块执行,其它代码一律不执行,可以使用:
Class.forName(“完整类名”);
这个方法的执行会导致类加载,类加载时,静态代码块执行
package day25.test;
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
//实例化对象 调用getClass方法
Student stu = new Student();
Class cla1 = stu.getClass();
System.out.println(cla1);
//第二种方式
Class cla2 = Student.class;
System.out.println(cla2);
//第三种方式 只要完整的包名加类名 无需项目名
Class cla3 =Class.forName("day25.test.Student");
System.out.println(cla3);
}
}
四、反射-获取构造方法
package day25.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test03 {
/**
* 获取所有公有的构造方法
*/
public void show1() throws ClassNotFoundException {
Class cla = Class.forName("day25.test.Student");
//调用方法可以获取所有公有的构造
Constructor[] cons = cla.getConstructors();
for (Constructor c : cons) {
System.out.println(c);
}
}
//获取所有的构造方法
public void show2() throws ClassNotFoundException {
Class cla = Class.forName("day25.test.Student");
Constructor[] cons = cla.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
}
//获取单个公有构造方法 并实例化对象
public void show3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cal = Class.forName("day25.test.Student");
//获取单个共有的构造 ,没有共有构造方法或者多个都报错
Constructor con = cal.getConstructor();
System.out.println(con);
//通过反射来实例化这个对象
Student stu = (Student) con.newInstance();
System.out.println(stu.name);
}
//获取单个私有的构造 单个无s 返回一个数据 多个加s 英语的复数 返回数组
public void show4() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cla = Class.forName("day25.test.Student");
Constructor con =cla.getDeclaredConstructor(String.class,int.class);
//通过暴力反射去除私有
con.setAccessible(true);
//通过构造方法反射来实例化这个对象
Student stu =(Student)con.newInstance("小明",23);
System.out.println(stu.name);
//私有属性就无法直接通过对象名.属性调用
//System.out.println(stu.age);
}
}
五、反射-获取成员方法
package day25.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Test04 {
//获取所有公有的方法
public void show1() throws ClassNotFoundException {
Class<?> cla = Class.forName("day25.test.Student2");
Method [] methods =cla.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
//获取所有的方法 不包括父类的方法
public void show2() throws ClassNotFoundException {
Class<?> cla = Class.forName("day25.test.Student2");
Method [] methods =cla.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
//获取反射公有的方法
public void show3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> cla = Class.forName("day25.test.Student2");
//获取单个公有的方法
//第一个参数 方法的名称 第二个参数 方法参数的类型的.class
Method method = cla.getMethod("eat",String.class);
//通过反射来实例化对象
Constructor con =cla.getConstructor();
//实例化对象
Object obj =con.newInstance();
//调用方法invoke (Object obj,Object ...args)
//第一个时调用方法的对象 第二个参数时多需要的具体的值
//返回值就是参数的返回值
Object ob =method.invoke(obj,"梨子");
System.out.println(ob);
}
public void show4() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> cla = Class.forName("day25.test.Student2");
//获取所有的方法
Method method= cla.getDeclaredMethod("sleep");
//使用暴力反射去除私有
method.setAccessible(true);
//通过反射来实例化对象
Constructor con = cla.getConstructor();
//实例化对象
Object obj =con.newInstance();
method.invoke(obj);
}
}
七、通过反射来忽略集合泛型
泛型是在编译期间起作用的,在编译后的.class文件中是没有泛型的。所有泛型,本质都是通过Object处理的。反射是在编译后操作.class文件,所以可以越过泛型
理解:泛型通过object在编译期间转为对应类型,编译完后生成.class文件,这时反射在操作.class文件,所以可以忽略泛型
使用反射给集合泛型添加了其他类型数据后
增强for循环需要返回值类型需要为Object,否则遍历输出时会再一次进行强转,然后可能报错
Integer num = list.get(2); 会报错 类转换异常
Object num = list.get(2); 正常运行
list.add(“ss”); 编译就报错 不能添加String类型
//通过反射来忽略集合泛型
public void show5() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Integer> list =new ArrayList<>();
list.add(123);
list.add(344);
//获取当前对象的Cla对象
Class cla =list.getClass();
//获取集合的add方法
Method method =cla.getMethod("add",Object.class);
//调用集合中的add方法
method.invoke(list,"add");
//增强for循环需要返回值类型需要为Object,否则遍历输出时会再一次进行强转,然后可能报错
for (Object obj : list) {
System.out.println(obj);
}
//Integer num = list.get(2); 会报错 类转换异常
System.out.println(list.get(2));
Object num = list.get(2);
Object object = list.get(0);
System.out.println(list);
//list.add("ss"); 编译就报错 不能添加String类型
}
案例1 配置文件
step01 需求 在不改变任意的代码的前提下 调用任何类中任何方法
step02 分析
1.需要调用一个类中的方法
完整的包名 方法的名称
2.完整的包名 方法的名称 只能存放在配置文件中 只能存在Properties对象中
3.可以通过反射来动态的来进行调用
step03代码结构
配置文件创建方法,与工具类在同一个包下,右键包名,new->file->命名(名字后缀必须为.properties)->创建成功添加成功内容
其他文件类型也可以用file创建,后缀名写好就行,例如1.txt,就会创建文本文件
实体类
package day25.test;
public class Student1 {
private void show(String n,int num,String w){
System.out.println(n+"\t"+num+"\t"+w);
}
public void showInfo(){
System.out.println("我是调用的showInfo方法");
}
}
配置文件
classname=day25.test.Student1
methodname=show
parametertypes=String,int,String
result=false
工具类
package day25.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 工具类
*/
public class PropertiesUtils {
//私有的属性
private static PropertiesUtils propertiesUtils;
private Properties pro;
//私有的构造
private PropertiesUtils(){
try {
pro = new Properties();
//通过反射来获取
//文件必须与当前类在同一包下
InputStream is =PropertiesUtils.class.getResourceAsStream("className.properties");
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
}
//提供一个公有的方法
public static synchronized PropertiesUtils getInstance(){
if(propertiesUtils == null){
propertiesUtils =new PropertiesUtils();
}
return propertiesUtils;
}
//提供一个方法 通过键来获取值
public String getValue(String key){
return pro.getProperty(key);
}
}
测试类
package day25.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Factory {
public static void main(String args[]){
showInfo();
}
public void showInfo(){
try {
//通过PropertiesUtils 工具获取配置文件信息
String className =PropertiesUtils.getInstance().getValue("classname");
String methodName =PropertiesUtils.getInstance().getValue("methodname");
//获取class对象
Class cla =Class.forName(className);
//获取构造方法
Constructor con =cla.getConstructor();
//实例化对象
Object obj =con.newInstance();
//获取参数列表
Class [] classes =getforClass();
//非空验证
if(classes==null || classes.length<=0){
//获取方法的对象
Method m = cla.getDeclaredMethod(methodName);
m.setAccessible(true);
//调用其方法
m.invoke(obj);
}else {
Method m =cla.getDeclaredMethod(methodName,classes);
m.setAccessible(true);
m.invoke(obj,"张三",18,"爱好男");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
//获取配置文件中的方法参数类型数组
public Class[] getforClass() {
//获取配置文件参数的信息 判断是否有参数
//配置文件即 同一个包 右键 new ->file->命名->添加内容
String str = PropertiesUtils.getInstance().getValue("parametertypes");
//进行非空验证
if(str == null || str ==""){
return null;
}
//根据逗号进行分割
//定义一个集合来进行存储
List<Class> list= new ArrayList<>();
String [] arrays =str.split(",");
for (String s : arrays) {
if(s.equals("String")){
list.add(String.class);
}else if(s.equals("int")){
list.add(int.class);
}else {
list.add(Object.class);
}
}
return list.toArray(new Class[list.size()]);
}
}
需要输出不同内容 即更改foctory类反射调用方法传入的参数即可,需要调用Student1的showInfo方法,即在配置文件中 将methodname=show 改为 methodname = showInfo parametertypes=String,int,String 改为parametertypes= 或者直接删除这行
八、反射-获取成员变量
package day25.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Test06 {
/**
* 获取所有公有的属性
*/
public void show1() throws ClassNotFoundException {
Class<?> cla = Class.forName("day25.test.Student");
//获取所有的属性 调用其方法
Field [] fields =cla.getFields();
for (Field f : fields) {
System.out.println(f);
}
}
/**
* 获取所有的属性 包括私有的
* @throws ClassNotFoundException
*/
public void show2() throws ClassNotFoundException {
//获取Class对象
Class<?> cla = Class.forName("day25.test.Student");
//获取所有的属性 调用其方法
Field [] fields =cla.getDeclaredFields();
for (Field f : fields) {
System.out.println(f);
}
}
/**
* 获取单个公有的属性
*/
public void show3() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> cla = Class.forName("day25.test.Student");
//获取所有的属性 调用其方法
Field f =cla.getField("name");
//获取构造方法
Constructor con =cla.getConstructor();
//实例化对象
Object obj =con.newInstance();
//给属性进行设置值 第一个参数 赋值的对象 赋的具体的数据
//public void set(Object obj,Object Value)
f.set(obj,"张三");
//通过对象来获取值
Student stu =(Student) obj;
System.out.println(stu.name);
}
public void show4() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> cla = Class.forName("day25.test.Student");
//获取所有的属性 调用其方法
Field f =cla.getDeclaredField("sid");
f.setAccessible(true);
Constructor con =cla.getConstructor();
Object obj =con.newInstance();
f.set(obj,123);
Object ob =f.get(obj);
System.out.println(ob);
}
}
反射小总结
1.用反射class创建对象,实质是用无参构造,所以该类需要有无参构造才能用此方式 Object p = cla.newInstance();
2.得到类对象就能得到 构造方法getConstructor 成员方法getMethod 成员变量getFiled
3.加s 即得到多个即所有 加Declared 即能得到私有 加方法参数即得到指定方法
4.单数返回一个对象类型,复数返回一个对象类型数组
5.Modifier.toString(类或方法或属性.getModifiers()) 得到相应的修饰符 public private
6.构造方法或成员方法.getParameterTypes(); 得到方法的参数类型数组
7.m.getReturnType().getSimpleName() 方法返回值类型
8.f.getType().getSimpleName()属性类型
9. m.getName() 方法名 f.getName() 属性名 cla.getSimpleName() 类名
10.setAccessible(true); 暴力解除私有 之后不安全 其他类也能访问私有属性
11.属性.set(实例化的对象名,赋值的属性值) get(实例化的对象名) 赋值取值
12.方法.invoke(实例化的对象名,该方法需传入的实参1,实参2) 得到方法的返回值,void类型返回null
13.构造方法.newInstance();无参构造不传参数,有参构造传需要的参数
14.method.getParameters() parameters[i].getName() 得到默认的形参命名 arg0
package day25.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> cla = Class.forName("day25.demo.Person");
//获取包名加类名
System.out.println(cla.getName());
//获取类名
System.out.println(cla.getSimpleName());
//用反射class创建对象,实质是用无参构造,所以该类需要有无参构造才能用此方式
Object p = cla.newInstance();
//获取所有的方法
Constructor<?>[] declaredConstructors = cla.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
//declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor);
}
//获取单独指定的构造方法 无参构造并实例化
Constructor<?> con = cla.getConstructor();
Object o = con.newInstance();
Person p1 = (Person)o;
//获取有参构造并实例化
Constructor<?> con1 = cla.getConstructor(String.class, int.class);
Person p2 = (Person) con1.newInstance("张三", 18);
//获取所有的方法
Method[] declaredMethods = cla.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
//获取指定的方法 第一个参数 方法的名称 第二个参数 方法参数的类型的.class
// 调用 调用方法invoke (Object obj,Object ...args)
// 第一个时调用方法的对象 第二个参数时多需要的具体的值 返回值就是参数的返回值
Method setName = cla.getMethod("setName", String.class);
setName.invoke(p2,"换成李四啦");
System.out.println(p2);
//其值是该方法的返回值,为void 返回null 有具体的返回值就是该返回值
System.out.println(setName.invoke(p2,"换成李四啦"));
//获取所有的属性
Field[] declaredFields = cla.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
//获取指定的属性
Field age = cla.getDeclaredField("age");
//因为是私有的 需要先破解 打破封装
age.setAccessible(true);
//获取属性
System.out.println(age.get(p2));
//设置属性
age.set(p2,20);
System.out.println(age.get(p2));
}
}
案例 反编译类
package day25.demo;
import java.lang.reflect.*;
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException {
StringBuilder sb = new StringBuilder();
//获取类对象
Class cla = Class.forName("day25.demo.Person");
//反编译类名
sb.append(Modifier.toString(cla.getModifiers())+" class "+cla.getSimpleName()+"{\n");
//获取所有的属型 反编译属性
Field [] fields =cla.getDeclaredFields();
for (Field field : fields) {
sb.append("\t");
//获取属性的修饰符列表,返回的修饰符是一个数字,每个数字对应修饰符表的一个修饰符
//用Modifier.toString() 转为字符串
sb.append(Modifier.toString(field.getModifiers()));
if(field.getModifiers() !=0){
sb.append(" ");
}
//获取属性的类型
sb.append(field.getType().getSimpleName());
sb.append(" ");
//获取属性的名字
sb.append(field.getName());
sb.append(";\n");
}
//获取构造方法 反编译构造方法
Constructor[] cons = cla.getDeclaredConstructors();
for (Constructor con : cons) {
sb.append("\t");
sb.append(Modifier.toString(con.getModifiers()));
sb.append(" "+cla.getSimpleName()+" ");
sb.append("(");
//获取形参的类型
Class[] parameterTypes = con.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
sb.append(parameterTypes[i].getSimpleName());
sb.append(" "+fields[i].getName());
if(i != parameterTypes.length-1){
sb.append(",");
}
}
if(parameterTypes.length==0){
sb.append("){\n\t}\n");
}else {
sb.append("){\n\t");
for (int i = 0; i < fields.length; i++) {
sb.append("\t"+"this."+fields[i].getName()+" = "+fields[i].getName()+";");
sb.append("\n\t");
}
sb.append("}\n");
}
}
//获取方法 反编译方法
Method[] methods = cla.getDeclaredMethods();
for (Method method : methods) {
sb.append("\t");
//获取修饰符列表
sb.append(Modifier.toString(method.getModifiers())+" ");
//获取方法的返回值类型
sb.append(method.getReturnType().getSimpleName()+" ");
//获取方法名
sb.append(method.getName()+"(");
//方法形参的类型
Class<?>[] parameterTypes = method.getParameterTypes();
//方法形参默认命名 parameters[i].getName() args0 args1
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameterTypes.length; i++) {
sb.append(parameterTypes[i].getSimpleName());
sb.append(" "+parameters[i].getName());
if(i != parameterTypes.length-1){
sb.append(",");
}
}
sb.append("){}\n");
}
sb.append("}");
System.out.println(sb);
}
}