反射
- 定义:动态获取类的字节码文件,并对其成员进行抽象
整体含义:就是通过字节码文件直接创建对象
- 过程:
1.获取字节码文件对象
2.通过字节码文件对象获取对应的实例对象
3.给属性赋值(通过从属性中提取出来的类---Field)
4.调用方法(通过从方法中提取的类--Method)
- 原理
- 获取字节码文件对象
1.通过Object提供的getClass()方法。(首先必须要有一个对象 XXX)
2.通过每种数据类型都有的一个class属性 (在使用的位置必须当前类是可见的,因为这里要显示的使用这个类名,对类的依赖性太强,使用不方便 XXX)
3.Class类提供的一个静态方法static Class forName(String str) str是包名加类名(我们只需要提供一个当前类的字符串形式即可) eg:要保证至少字符串对应的类是存在的
- 代码
package com.qf.test; public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { //1.通过Object提供的getClass()方法 fun1(); //2.通过每种数据类型都有的一个class属性 fun2(); //3.Class类提供的一个静态方法forName(字符串) 字符串:包名+类名 fun3(); } public static void fun1() { Person person = new Person(); Class<?> class1 = person.getClass(); Class<?> class2 = person.getClass(); System.out.println(class1 == class2);//true } public static void fun2() { Class<?> class1 = Person.class; System.out.println(class1.getName()); } public static void fun3() throws ClassNotFoundException { //注意:要保证至少字符串对应的类是存在的 Class<?> class1 = Class.forName("com.qf.test.Person"); } }
- 通过字节码文件对象获取对应的实例对象
1.通过无参的构造方法创建实例对象
2.通过有参的构造方法创建实例对象
- 代码
package com.qf.test; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; //2.通过字节码文件对象获取对应的实例对象 public class Demo2 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { //普通方式 //Person person = new Person(); //通过反射创建普通对象 Class<?> class1 = Class.forName("com.qf.test.Person"); //方法一:通过无参的构造方法创建实例对象 fun1(class1); //方法二:通过有参的构造方法创建实例对象 fun2(class1); } //方法一:通过无参的构造方法创建实例对象 public static void fun1(Class<?> cls) throws InstantiationException, IllegalAccessException { //创建实例对象 //这里相当于在newInstance方法的内部调用了无参的构造方法 Object object = cls.newInstance(); Person person = (Person)object; person.setName("bingbing"); System.out.println(person.getName()); } //方法二:通过有参的构造方法创建实例对象 public static void fun2(Class<?> cls) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //先得到有参的构造方法 //这里要写参数的字节码文件对象形式 所有的类型都有字节码文件对象 //相当于 public Person(String name, int age) Constructor constructor = cls.getConstructor(String.class,int.class); Object object = constructor.newInstance("bingbing",18); System.out.println(object); } }
- 给属性赋值(通过从属性中提取出来的类---Filed)
package com.qf.test; import java.lang.reflect.Field; public class Demo3 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException { Person person = new Person(); //person.name = "bingbing"; //使用反射实现 //1.获取字节码文件对象 Class<?> class1 = Class.forName("com.qf.test.Person"); //2.获取实例对象 Object object = class1.newInstance(); //3.调用属性 //注意:如果想使用getField,name属性必须是public的 //Field field1 = class1.getField("name"); //如果name是私有的,我们可以这样做 ,忽略权限 Field field1 = class1.getDeclaredField("name"); field1.setAccessible(true); //赋值 //第一个参数:关联的具体对象 //第二个参数:赋的值 field1.set(object, "bing"); System.out.println(field1.get(object)); } }
- 调用方法(通过从方法中提取出来的类----Method)
1.调用非静态无参
2.调用非静态有参
3.调用静态有参
package com.qf.test; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Demo4 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { //使用反射实现 //1.获取字节码文件对象 Class<?> class1 = Class.forName("com.qf.test.Person"); //调用非静态无参 fun1(class1); //调用非静态有参 fun2(class1); //调用静态有参 fun3(class1); } //调用非静态无参 public static void fun1(Class<?> cla) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { //2.获取实例对象 Object object = cla.newInstance(); //3.通过反射得到方法 Method method = cla.getMethod("show"); //4.调用方法,通过调用invoke方法实现 method.invoke(object); } //调用非静态有参 public static void fun2(Class<?> cla) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //2.先得到有参的构造方法 Constructor<?> constructor = cla.getConstructor(String.class,int.class); Object object = constructor.newInstance("bingibn",10); //3.通过反射得到方法 Method method = cla.getMethod("callPhone",String.class); //4.调用方法,通过调用invoke方法实现 method.invoke(object,"110"); } //调用静态有参 public static void fun3(Class<?> cla) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //3.通过反射得到方法 Method method = cla.getMethod("run",int.class); //4.调用方法,通过调用invoke方法实现 method.invoke(null,11); } }
代理设计模式
- 可以参考:https://blog.youkuaiyun.com/WangQYoho/article/details/77584832
- 静态代理
作用:根据OCP(对扩展开放,对修改关闭)的原则,在不改变原来类的基础上,给这个类增加额外的功能
缺点:代理对象要保证跟目标对象实现同样的接口,在维护的时候两个对象都要维护,而且代理对象实现的接口是死的,这时如果要给想实现不同功能的多个目标对象添加代理对象的话,要添加很多个类
- 动态代理
动态生成代理对象的方法--通过JDK内置的java.lang.reflect.Proxy动态代理类完成代理对象的创建
参数一:这里代表类加载器,代理类的类加载器要与目标类的类加载器一致,类加载器用来装载内存中的字节码文件
参数二:代理类与目标类实现的接口必须有相同的,即指定给代理类的接口,目标类必须实现了
参数三:代理类的构造方法生成的对象--注意:指定给构造方法的参数要使用Objectpublic static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
代理对象调动方法的时候,invoke方法会自动被调用
package com.qf.invocation1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //使用动态代理 public class Test { //模拟功能:bingbing和chenchen找房住 public static void main(String[] args) { //静态代理 // Bingbing bingbing = new Bingbing(); // //bingbing.findHouse(); // Agent agent = new Agent(bingbing); // agent.findHouse(); //动态代理 TestInter testInter = new Bingbing(); //调用动态代理的方法实现功能 /** *动态生成代理对象的方法--通过JDK内置的java.lang.reflect.Proxy动态代理类完成代理对象的创建 *参数一:这里代表类加载器,代理类的类加载器要与目标类的类加载器一致,类加载器用来装载内存中的字节码文件 *参数二:代理类与目标类实现的接口必须有相同的,即指定给代理类的接口,目标类必须实现了 *参数三:代理类的构造方法生成的对象--注意:指定给构造方法的参数要使用Object * */ // TestInter object = (TestInter)Proxy.newProxyInstance(testInter.getClass().getClassLoader(), new Class[] {TestInter.class}, new Agent(testInter)); //代理对象调动方法的时候,invoke方法会自动被调用 // object.findHouse(); // // TestEat testEat = new Langlang(); // TestEat object1 = (TestEat)Proxy.newProxyInstance(testEat.getClass().getClassLoader(), new Class[] {TestInter.class,TestEat.class}, new Agent(testEat)); // object1.eat(); //进一步优化----直接使用InvocationHandler创建匿名内部类干活儿,不再需要Agent类 TestInter object2 = (TestInter)Proxy.newProxyInstance(testInter.getClass().getClassLoader(), new Class[] {TestInter.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("扣一个月的房租作为中介费"); Object object = method.invoke(testInter, args); System.out.println("哈哈大笑"); return object; } } ); object2.findHouse(); TestEat testEat = new Langlang(); TestEat object3 = (TestEat)Proxy.newProxyInstance(testEat.getClass().getClassLoader(), new Class[] {TestInter.class,TestEat.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("先洗后"); Object object = method.invoke(testEat, args); System.out.println("哈哈大笑"); return object; } }); object3.eat(); //使用工厂方法 TestInter testInter3 = TestFactory.getAgentFactory(testInter); testInter3.findHouse(); } }
代理类实现InvocationHandler接口并实现它的invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
eg:这个方法在调用接口方法的时候会被自动调用
参数一:代理对象的引用
参数二:目标对象的方法
参数三:目标对象的方法参数
package com.qf.invocation1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class Agent implements InvocationHandler{ //先给他个人 //注意:指定给构造方法的参数要使用Object Object person; public Agent(Object person) { super(); this.person = person; } // public void findHouse() { // System.out.println("扣一个月的房租作为中介费"); // person.findHouse(); // System.out.println("哈哈大笑"); // } /** * 接口中的方法 * 主要:这个方法在调用接口方法的时候,会被自动调动 * 参数一:代理对象的引用 * 参数二:目标对象的方法 * 参数三:目标对象的方法参数 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("扣一个月的房租作为中介费"); Object object = method.invoke(person, args); System.out.println("哈哈大笑"); return object; } }
目标代理对象
package com.qf.invocation1; public class Bingbing implements TestInter { public void findHouse() { System.out.println("冰冰来西三旗找房"); } }
package com.qf.invocation1; public class ChenChen implements TestInter { public void findHouse() { System.out.println("晨晨去日本找房"); } }
package com.qf.invocation1; public class Langlang implements TestEat{ @Override public void eat() { System.out.println("郎朗吃饭"); } }
目标对象的接口
package com.qf.invocation1; public interface TestInter { public void findHouse(); }
package com.qf.invocation1; public interface TestEat { public void eat(); }
- 创建一个工厂类--------用于创建代理对象
package com.qf.invocation1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //创建一个工厂类---用于创建代理对象 public class TestFactory { //工厂方法 public static TestInter getAgentFactory( final TestInter test) { //final TestInter test = new Bingbing(); TestInter agent = (TestInter)Proxy.newProxyInstance(test.getClass().getClassLoader(), new Class[]{TestInter.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("扣一半房租做中介费"); // TODO Auto-generated method stub //通过反射的方法调用具体对象的方法 Object object = method.invoke(test, args); System.out.println("哈哈大笑"); return object; } }); return agent; } }
Java-day11-Reflect和动态代理
最新推荐文章于 2025-04-19 01:30:00 发布