Javase 高级技术 —— 01 反射
本系列为笔者学习Javase的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员Java+AI智能辅助编程全套视频教程,java零基础入门到大牛一套通关》,章节分布参考视频教程,为同样学习Javase系列课程的同学们提供参考。
01 单元测试
单元测试就是针对最小的功能单元——方法,编写测试代码对其进行正确性测试。
咱们之前是如何进行单元测试的?有啥问题?
- main方法编写代码,调用其他方法测试
- 无法实现自动化测试
- 无法得到测试的报告
Junit
单元测试框架可以用来对方法进行测试,其是第三方公司开源出来的。
优点
- 自动化测试,且各自独立
- 自动生成测试报告
02 反射
反射就是加载类,并允许以编程的方式解剖类中的各种成分,包括成员变量、成员方法、构造器。
操作步骤
① 加载类,获取类的字节码(class
类对象)
Class c1 = 类名.class
- 调用
Class
提供方法:public static Class forName(String package);
- 调用
Object
提供方法:public Class getclass(); Class c3 = 对象.getClass(0);
package ReflectDemo;public class ReflectDemo {public static void main(String[] args) throws Exception {//目标:认识反射,获取类的Class对象的三种方式//1.类.class [类本身]Class c1 = Student.class;System.out.println(c1);//2.Class.forName [类的全类名]Class c2 = Class.forName("ReflectDemo.Student");System.out.println(c1);//3.对象.getClass() [类本身]Student s = new Student();Class c3 = s.getClass();System.out.println(c3);}
}
② 获取类的构造器(Constructor
对象)
③ 获取类的成员变量(Field
对象)
④ 获取类的成员方法(Method
对象)
ReflectDemo.java
package ReflectDemo;import org.junit.Test;import javax.swing.plaf.metal.MetalTheme;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.MalformedParametersException;
import java.lang.reflect.Method;public class ReflectDemo2 {@Testpublic void getClassInfo() {//目标:获取类的信息(成员变量、成员方法、构造器)//1.获取Class类对象Class c1 = Dog.class;System.out.println(c1.getName());System.out.println(c1.getSimpleName());}//2.获取Constructor构造器对象@Testpublic void getConstructorInfo() throws Exception {Class c1 = Dog.class;Constructor[] cons = c1.getDeclaredConstructors();for(Constructor con : cons){System.out.println(con.getName() + "(" + con.getParameterCount() + ")");}Constructor con0 = c1.getDeclaredConstructor();System.out.println(con0.getName() + "(" + con0.getParameterCount() + ")");Constructor con1 = c1.getDeclaredConstructor(String.class, int.class);System.out.println(con1.getName() + "(" + con1.getParameterCount() + ")");con0.setAccessible(true); //暴力反射,强制访问Dog d1 = (Dog) con0.newInstance();System.out.println(d1);Dog d2 = (Dog) con0.newInstance("小白", 3);System.out.println(d2);}//3.获取Field成员变量对象@Testpublic void getFieldInfo() throws Exception {Class c1 = Dog.class;Field[] fields = c1.getDeclaredFields();for(Field field : fields){System.out.println(field.getName() + "(" + field.getType().getName() + ")");}Field field0 = c1.getDeclaredField("hobby");System.out.println(field0.getName() + "(" + field0.getType().getName() + ")");Dog d1 = new Dog("泰迪", 2);field0.setAccessible(true); //暴力反射field0.set(d1, "玩球");String hobby = (String) field0.get(d1);System.out.println(hobby);}//4.获取Method成员方法对象@Testpublic void getMethodInfo() throws Exception {Class c1 = Dog.class;Method[] methods = c1.getDeclaredMethods();for(Method method : methods){System.out.println(method.getName() + "(" + method.getParameterCount() + ")");}Method eat0 = c1.getDeclaredMethod("eat");System.out.println(eat0.getName() + "(" + eat0.getParameterCount() + ")");Method eat1 = c1.getDeclaredMethod("eat", String.class);System.out.println(eat1.getName() + "(" + eat1.getParameterCount() + ")");Dog d1 = new Dog("泰迪", 2);eat0.setAccessible(true); //暴力反射Object rs1 = eat0.invoke(d1); //d1.eat()System.out.println(rs1); //nullObject rs2 = eat1.invoke(d1,"牛肉");System.out.println(rs2); //cheers~}
}
Dog.java
package ReflectDemo;public class Dog {private String name;private int age;private String hobby;private void eat(){System.out.println("小狗吃饭");}public String eat(String food){System.out.println("小狗吃" + food);return "cheers~";}private Dog() {System.out.println("无参构造器执行");}private Dog(String name) {System.out.println("1号有参构造器执行");this.name = name;}public Dog(String name, int age) {System.out.println("2号有参构造器执行");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;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +", hobby='" + hobby + '\'' +'}';}
}
03 反射的作用
- 可以得到一个类的成员变量、成员方法、构造器对象然后操作
- 可以破坏封装性
- 可以绕过泛型的约束
- 可以设计
Java
高级框架
package ReflectDemo;import java.lang.reflect.Method;
import java.util.ArrayList;public class ReflectDemo3 {public static void main(String[] args) throws Exception{ArrayList<String> list = new ArrayList<>();list.add("赵敏");list.add("黄蓉");list.add("小龙女");list.add("王语嫣");//list.add(1988);//list.add(true);Class c1 = list.getClass();Method add = c1.getDeclaredMethod("add", Object.class);add.invoke(list, 9.9);add.invoke(list, true);System.out.println(list);}
}
04 案例:使用反射做一个简易版的框架
需求:对于任意一个对象,该框架都可以把对象的字段名和对应值保存到文件中去。
实现步骤:
① 定义一个方法,可以接收任意对象。
② 每收到一个对象后,使用反射获取该对象的Class
对象,然后获取全部的成员变量。
③ 遍历成员变量,然后提取成员变量在该对象中的具体值。
④ 把成员变量名、和其值,写出到文件中去即可。