目录
反射是什么?
通过反射可以获取一个类的成员(字段、方法、构造)
举例:IDEA 中查看一个类/方法要传入什么参数 就是通过反射 还有调用一个类/对象内部的方法,点.
出来的方法列表 就是反射出来的。
- 获取任意一个类中的所有信息
- 结合配置文件动态创建对象
动态代理是什么?
防止侵入式修改 (也就是直接修改一个类 导致程序崩溃)。
代理可以无侵入式的给对象增强其他的功能。
对象有什么方法 需要被代理,代理就一定有对应的方法。(通过接口通知代理 要代理什么方法)
一、获取class字节码文件的三种方式
- Class.forName(“类的全类名”);
- 类名.class; 属性
- 对象.getClass();
//1.第一种方式
// 全类名:包名+类名
//使用场景:最常用,当类被创建编译后就可以用
Class aClass = Class.forName("com.reflect1.Student");
System.out.println(aClass);//class com.reflect1.Student
//2.第二种方式
//一般就是当作参数传递,比如多线程中的同步锁使用
Class aClass1 = Student.class;
System.out.println(aClass == aClass1);//true
//3.第三种方式
//创建了这个类的对象后,就可以用这个方法
Student student = new Student();
Class aClass2 = student.getClass();
System.out.println(aClass1 == aClass2);//true
二、反射获取构造方法 (Constructor)
三、反射获取成员变量 (Field)
四、反射获取成员方法 (Method)
五、动态代理分析与代码实现
- 代理里面存放需要被代理的方法。
- 通过接口 存放要被代理的方法,对象和代理都要实现该接口
实体类:
接口:
public interface Start {
String sing(String song);
void dance();
}
代理:
public class ProxyUtil {
public static Start createProxy(BigStart bigStart) {
//参数一:指定用哪个类加载器,去加载生成的代理对象
//参数二:有哪些接口
//参数三:指定生成的代理对象要做什么
Start start = (Start) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Start.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* 参数一 代理的对象
* 参数二 需要执行的方法
* 参数三 调用方法需要的参数
* */
if ("sing".equals(method.getName())) {
System.out.println("开始唱歌吧!");
} else if ("dance".equals(method.getName())) {
System.out.println("开始跳舞吧!");
}
return method.invoke(bigStart, args);
}
});
return start;
}
}
测试:
BigStart bigStart = new BigStart("鸡哥");
Start start = ProxyUtil.createProxy(bigStart);
String result = start.sing("只因你太美");
System.out.println(result);
start.dance();
综合练习
保存任意对象数据
public class ReflectDemo1 {
public static void main(String[] args) throws IllegalAccessException, IOException {
Student s = new Student("张三", 18);
saveObject(s);
}
private static void saveObject(Object obj) throws IllegalAccessException, IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("A-SocketNet\\a.txt"));
Class<?> aClass = obj.getClass();
Field[] df = aClass.getDeclaredFields();
for (Field field : df) {
field.setAccessible(true);
String name = field.getName();
Object value = field.get(obj);
System.out.println(name+"="+value);
bw.write(name+"="+value);
bw.newLine();
}
bw.close();
}
}
利用反射动态的创建对象和运行方法
/*
反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
*/
//从配置文件中获取 全类名与要调用的方法
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("A-SocketNet\\prop.properties");
prop.load(fis);
System.out.println(prop);//{classname=com.reflect2.Teacher, method=teach}
//配置文件中获取数值
Object classname = prop.get("classname");
Object method = prop.get("method");
Class aClass = Class.forName(String.valueOf(classname));
// 反射创建有参构造
Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class, double.class);
Object o1 = declaredConstructor.newInstance("1", 2.9);
System.out.println(o1);
// 反射创建无参构造
Constructor constructor = aClass.getDeclaredConstructor();
Object o = constructor.newInstance();
System.out.println(o);
// 反射 调用 方法
Method declaredMethod = aClass.getDeclaredMethod(String.valueOf(method));
declaredMethod.invoke(o);
配置文件:
相关实体类:
运行效果:
总结
反射: