反射技术
一、反射概述
>JAVA反射机制是在运行状态中,对任意一个类,能够知道这个类的所有属性和方法
>对于任意一个对象,都能够调用它的任意一个方法和属性
>这种动态获取信息以及动态调用对象的方法的功能称为JAVA语言的反射机制。
>要想解剖一个类,必须先要获取到该类的字节码文件对象
>而解剖使用的就是Class类中的方法,所以先要获取每个字节码文件对应的Class类型对象。
三种获取方式
* a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件
* b:静态属性class,锁对象
* c:Class类中静态方法forName(),读取配置文件
二、通过反射获取带参构造方法并使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Demo3_Constructor { /** * Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, * 就不能这样创建了,可以调用Class类的getConstructor * (String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance * ("张三",20)方法创建对象 * @throws Exception */ public static void main(String[] args) throws Exception { Class clazz = Class.forName("cn.wj.bean.Person"); //Person p = (Person) clazz.newInstance(); 通过无餐构造创建对象 //System.out.println(p); Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 System.out.println(p); } } |
三、通过反射获取成员变量并使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class Demo4_Field { /** * Class.getField(String)方法可以获取类中的指定字段(可见的), * 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, * 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值 * @throws Exception */ public static void main(String[] args) throws Exception { Class clazz = Class.forName("cn.wj.bean.Person"); Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 //Field f = clazz.getField("name"); //获取姓名字段 //f.set(p, "李四"); //修改姓名的值 Field f = clazz.getDeclaredField("name"); //暴力反射获取字段 f.setAccessible(true); //去除私有权限 f.set(p, "李四"); System.out.println(p); } } |
四、通过反射获取方法并使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class Demo5_Method { /** * Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, * Class...)方法可以获取类中的指定方法,调用invoke(Object, * Object...)可以调用该方法,Class.getMethod("eat") invoke(obj) * Class.getMethod("eat",int.class) invoke(obj,10) * @throws Exception */ public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.heima.bean.Person"); Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造 Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象 Method m = clazz.getMethod("eat"); //获取eat方法 m.invoke(p); Method m2 = clazz.getMethod("eat", int.class); //获取有参的eat方法 m2.invoke(p, 10); } } |
五、动态代理的概述和实现
1,概述
1)代理:本来应该自己做的事,请了别人来做,被请的人就是代理对象
2)动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代 理其实就是通过反射来生成一个代理
2,实现
* 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动 态代理对象。
* JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
* 最终会调用InvocationHandler的方法
* InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
MyInvocationHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("权限校验"); method.invoke(target, args); //执行被代理target对象的方法 System.out.println("日志记录"); return null; } } |
Test类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class Test { /** * @param args */ public static void main(String[] args) { StudentImp si = new StudentImp(); si.login(); si.submit(); System.out.println("-------------------------------"); MyInvocationHandler m = new MyInvocationHandler(si); Student s = (Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m); s.login(); s.submit(); } } |