反射作用
获取字节码文件里面的所有信息,包括构造方法、成员、成员方法,以及修饰他们的修饰符、类型和方法的返回值等等,只要是类里面的内容都能获取,获取之后可以动态的调用方法,动态的创建对象
获取类字节码文件对象
通过该对象可进行获取构造方法、成员、成员方法等操作
//获取Class对象的三种方法
//方法一:通过调用Class类里面的静态方法获取(包名 + 类名)
Class<?> class1 = Class.forName("a01CreatReflect.Student");
System.out.println(class1);
//方法二:通过字节码文件获取
Class<Student> class2 = Student.class;
System.out.println(class2);
//方法三:通过类实例化后通过实列化对象获取Class
Student student = new Student();
Class<? extends Student> class3 = student.getClass();
System.out.println(class3);
获取构造方法
declare可以获取到所有(包括私有)的构造方法,而没有declare修饰的只能获取公共的
获取成员
declare可以获取到所有(包括私有)的成员,而没有declare修饰的只能获取公共的
获取成员方法
declare修饰的将获取该类的所有方法(包括权限不够大的方法)
没有declare修饰的连该类继承的父类,以及实现的接口的公共方法都能获取到
应用场景
获取一个实例化对象的所有信息,并将他存进文件
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IOException {
//练习1:获取字节码文件里面的成员信息并保存进文件
Student s = new Student("zhangsan", 19, "睡觉");
Teacher t = new Teacher("niubi", 26);
//获取字节码文件对象
saveObj(s);
}
public static void saveObj(Object o) throws ClassNotFoundException, IllegalAccessException, IOException {
//获取当前对象的字节码文件对象
Class<?> aClass = o.getClass();
//创建高级字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("Reflect\\a.txt"));
//字符串对象
//通过字节码文件对象获取该字节码里面的所有成员变量并保存进文件
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
StringBuilder sb = new StringBuilder();
field.setAccessible(true);
//获取成员变量的名字
String name = field.getName();
//获取成员变量的值
Object value = field.get(o);
StringBuilder append = sb.append(name + "=" + value);
bw.write(append.toString());
bw.newLine();
}
bw.close();
}
无需修改源码,实现调用不同类的方法
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//练习2:不用修改代码,只需修改配置文件实现运行其他类的方法
//反射:从文件中获取内容进行操作
Properties p = new Properties();
//把文件内容全部加载进集合p
p.load(new InputStreamReader(new FileInputStream("Reflect\\a.txt")));
System.out.println(p);
//获取配置文件中的类名和方法名
String method = p.getProperty("method");
String classname = p.getProperty("Classname");
System.out.println(method);
System.out.println(classname);
//创建字节码文件对象
Class aClass = Class.forName(classname);
//通过字节码文件创建对象
//1.获取空参构造
Constructor con = aClass.getDeclaredConstructor();
//暴力反射:临时将构造方法的权限扩至最大
con.setAccessible(true);
//2.通过空参构造创建该类对象
Object o = con.newInstance();
//3.该对象调用方法(获取要调用的方法)
Method m = aClass.getDeclaredMethod(method);
//暴力反射:临时将方法的权限扩至最大
m.setAccessible(true);
m.invoke(o);
}
动态代理
当一个项目已经上线运营时,而需求发生变化,需要新功能,若直接修改源码(侵入式修改)需要重新测试,发布新版本等等操作很老告, 而动态代理的可以省去一堆繁琐的步骤
动态代理步骤:创建代理对象,代理对象调用要代理的方法