Java之反射&代理

反射:

  1. 创建对象的方式:
    1. new 对象
    2. 反射形式
  2. 定义:反射式 获取类信息的能力
  3. 类中的信息:
    1. 全局变量
    2. 方法
    3. 构造器
    4. 父类
    5. 接口
  4. 作用:从而更快的拿到类信息
  5. 类型信息状态:
    1. 磁盘状态
    2. 类对象状态
    3. 对象状态
  6. 获取类对象(三种状态):
    1. 磁盘状态:Class.forName("包名+ 类名")
    2. 类对象状态:类名.Class()
    3. 对象状态:对象名.getClass
  7. 反射的作用:
    1. 获取类信息:
      // 获取类信息
      Class class1 = Class.forName("qcby.fanshe.Person");     // 通常用于加载外部文件
      
      Class class2 = Person.class;        // 一般用于传参   --->在 Spring 项目里常用
      
      Person person = new Person();   // 通过对象的形式获取类信息
      person.getClass();
    2. 获取方法:
      1. getDeclaredFileds():获取所有修饰符修饰的变量
      2. getFields():获取所有 public 修饰符修饰的变量
      3. getDeclaredField("变量名"):获取指定的变量(不限修饰符)
      4. getField("变量名"):获取指定由 public 修饰符修饰的变量
        // 获取类对象
        Class class1 = Class.forName("fanshe.Person");     // 通常用于加载外部文件
        
        // 获取对象中的变量
        Field[] fields = class1.getFields();    //获取所有由 public 修饰的变量
        for(Field f : fields){
            System.out.println(f);
        }
        
        System.out.println("------------------------");
        Field[] declaredfields = class1.getDeclaredFields();    // 获取所有变量(不限修饰符)
        for(Field f : declaredfields){
            System.out.println(f);
        }
        
        System.out.println("------------------------");
        
        Field name = class1.getDeclaredField("name");   // 获取指定变量(不限修饰符)
        
        System.out.println(name);
        
        Field age = class1.getField("age");     // 获取 public 修饰的指定变量
        System.out.println(age);
    3. 修改值:
      1. set(对象名,值):需要给 set() 方法传入对象
        1. 对象的作用是在内存中的存储位置
      2. get(对象名):获取变量的值
      3. 暴力反射:
        1. private 修饰的变量想要赋值、取值操作需要暴力反射
          // 获取类对象
          Class class1 = Class.forName("fanshe.Person");     // 通常用于加载外部文件
          
          Person person = new Person();   //这里应该是反射形式创建对象 --> 这里为了方便由此创建对象
          
          // 获取对象中的变量
          Field sex = class1.getDeclaredField("sex");
          sex.set(person,20);     // 映射获取到的变量修改值需要 传入该对象 和 值  --> 对象是涉及到在内存中存储位置,变量存储在对象当中
          sex.get(person);        // 获取变量的值也需要传入该对象
          System.out.println(sex.get(person));    // 输出获取的值
          
          //获取变量
          Field name = class1.getDeclaredField("name");
          
          name.set(person,"李四");
          name.setAccessible(true);   // 这里 name 是由 private 修饰,赋值、取值 暴力反射
          name.get(person);    //获取变量的值
          
      4. 调用方法:
        1. 获取:
          1. getDeclaredMethods():获取所有的方法
          2. getMethods():获取 public 修饰符修饰的方法
          3. getDeclareMethed("方法名",反射类型值):无参方法可不写值
          4. getMethod("方法名",反射值类型):无参方法可不写值
            // 获取类对象
            Class class1 = Class.forName("fanshe.Person");     // 通常用于加载外部文件
            
            Person person = new Person();   //这里应该是反射形式创建对象 --> 这里为了方便由此创建对象
            
            // 获取对象中的变量
            Method[] declaredFields = class1.getDeclaredMethods();    //获取所有方法
            Method[] methods = class1.getMethods();     //获取所有 public 修饰的方法
            
            Method run = class1.getMethod("run");       // 获取指定的由 public 修饰的方法
            
            Method jump = class1.getMethod("jump", int.class);  // 获取指定方法(不限修饰符)  方法里面需要传参需要给 映射参数
        2. 使用:
          1. invoke(对象名)
          2. 暴力反射:private修饰的方法被调用式也需要暴力反射
            // 获取类对象
            Class class1 = Class.forName("fanshe.Person");     // 通常用于加载外部文件
            
            Person person = new Person();   //这里应该是反射形式创建对象 --> 这里为了方便由此创建对象
            
            // 获取对象中的变量
            Method[] declaredFields = class1.getDeclaredMethods();    //获取所有方法(不限修饰符)
            Method[] methods = class1.getMethods();     //获取所有 public 修饰的方法
            
            Method run = class1.getMethod("run");       // 获取指定的由 public 修饰的方法
            run.invoke(person);     //使用该方法 --> 需要传入对象
            
            Method jump = class1.getDeclaredMethod("jump", int.class);
            jump.setAccessible(true);   //这里 jump 方法由 private 修饰,调用方法需要暴力反射
            int num = (int) jump.invoke(person, 200);
            System.out.println(num);
            
            Method flay = class1.getDeclaredMethod("flay", Integer.class, String.class);
            flay.invoke(person,500,"鸟");
      5. 调用构造器:
        1. 获取构造器:
          1. getDeclaredConstructors():获取全部构造器
          2. getConstructors():获取全部由 public 修饰的构造器
          3. getConstructor():获取无参构造器
          4. getConstructor(反射类型值,反射类型值,…):获取有参构造器
            1. 根据参数类型匹配对应的构造器
        2. 创建对象:
          1. 构造器.newInstance("参数1","参数2",···)
            1. 无参构造器可不传参

​​​​​​​​​​​​​​​​​​​​​​​​​​​​

//获取类信息
Class class1 = Person.class;

//获取构造器
Constructor constructor1 = class1.getConstructor();  //获取无参构造器
Constructor constructor2 = class1.getConstructor(String.class, Integer.class, Character.class);  //获取有参构造器

//创建对象
Person person1 = (Person) constructor1.newInstance();   //使用无参构造器
Person person2 = (Person) constructor2.newInstance("张",55,'男');     //使用有参构造器

代理:

  1. 定义:
    1. 给目标对象提供一个代理对象,并且由代理对象控制对目标对象的引用
  2. 目的:
    1. 功能增强:通过代理业务对原有业务进行增强
    2. 访问控制:通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性
  3. 代理的角色:
    1. 抽象角色: 声明真实对象和代理对象共同接口
    2. 代理角色:代理对象角色内部含有真实对象的引用,从而可以操纵真实的对象
      1. 同时代理对象提供与真实对象相同的接口以便在任何时候都能代理真实对象
      2. 同时代理对象可以在执行过程真实对象操作时,附加其他的操作,相当于真实对象进行封装
    3. 真实角色:代理所代理的真实角色,是我们要引用的对象
  4. 静态代理:
    1. 核心类:
      public class ZhiFuBao{
          public void zhuanzhang(String A,String B,Double money){
              System.out.println(A + "向" + B + "转了" + money + "元");    
          }
      }
    2. 代理类:
      public class XXBao{    //代理类
          
      }
    3. 步骤:
      1. 首先创建一个私有的核心代理
      2. 继承目标接类的接口
        1. 接口:寻找到目标类的核心方法,以及方法中的参数(以便代理类做功能增强)
      3. 实现接口中的方法
      4. 对核心方法中的参数进行功能增强
      5. 调用核心方法
        public class XXBao{    //代理类
            //核心代理
            private ZhiFuBao zhiFuBao = new ZhiFuBao();
            @Override
            public void ZhuanZhang(String A, String B, Double money) {
                //进行功能增强
                yzA(A);
                yzB(B);
                yzM(money);
                //调用核心方法
                zhiFuBao.ZhuanZhang(A,B,money);
            }
            
            // 模拟验证 A 逻辑
            private void yzA(String A){
                System.out.println(A + "已被验证");
            }
            
            // 模拟验证 B 逻辑
            private void yzB(String B){
                System.out.println(B + "已被验证");
            }
            
            // 模拟验证 money 逻辑
            private void yzM(Double money){
                System.out.println(money + "已被验证");
            }
            
        }
    4. 动态代理:
      1. 目标类及接口
      2. 目标类也需要实现接口
        1. 接口:代理类可以通过接口寻找到目标类的核心方法,在代理类映射生成对象,执行该方法时,可以找到该方法
          public class ZhiFuBao extends ZhiFuBao1{
              //核心方法
              public void zhuanzhang(String A,String B,Double money){
                  System.out.println(A +"向"+ B + "转账"+ money + "元")
              }
          }
          
          //目标类接口
          public interface ZhiFuBao1{
              void zhuanzhang(Sting A,String B,Double money);
          }
      3. 代理类获取需要取代对象的类型
        1. 测试类通过扫描固定的包,获取到新增的类,通过反射形式创建对象
          public class XXBao{
              // 定义代理对象的类型
              private Object o = null;    
              public XXBao(Object o){
                  this.o = o;    
              }
          }
          
          class Test{
               public static void main(String[] args){
                  // 通过扫描固定的包,获取到新增的目标类,通过反射形式创建对象
                      //在此用简便写法
                  ZhiFuBao zhiFuBao = new ZhiFuBao();
                  XXBao xxBao = new XXBao(zhiFuBao);                                
              }
          }
      4. 通过目标对象的接口找到需要代理的核心方法
        1. 返回的值需要目标对象的接口类型去接收
          public class XXBao{
              // 定义代理对象的类型
              private Object o = null;    
              public XXBao(Object o){
                  this.o = o;    
              }
              
              //找到需要代理的核心方法
              public Object getProxyInstance(){    //固定写法
                  return Proxy.newProxyInstance(o.getClass.getClassLoader(),o.getClass().getInterface(),this)
              }
          }
      5. 继承 JDK 给的接口去实现代理:InvocationHandler
        public class XXBao implements InvocatonHandler{
            // 定义代理对象的类型
            private Object o = null;    
            public XXBao(Object o){
                this.o = o;    
            }
            
            //找到需要代理的核心方法
            public Object getProxyInstance(){    //固定写法
                return Proxy.newProxyInstance(o.getClass.getClassLoader(),o.getClass().getInterface(),this)
            }
            
            //实现代理
             /**
             *
             * @param proxy     代理类
             * @param method    方法
             * @param args      参数
             * @return
             * @throws Throwable
             */
            public Object invoke(Object proxy,Method method,Object[] args) throws Throwsble{
                //功能增强
                ······
                //反射形式执行核心方法
                method.invoke(o,args);    //传入当前对象,以及参数
                return null;    
            }
        }
      6. 测试类测试动态代理
        public class Test{
            public static void main(String[] args){
                //通过扫描固定的包获取到需要代理的目标对象
                //此处简写  直接 new 对象
                ZhiFuBao zhiFuBao = new ZhiFuBao();
                
                //调用代理类的构造器,定义代理对象的类型
                //调用getProxyIntance()方法获取到目标对象的接口,得到核心方法
                //要用目标对象的接口去接收
                ZhiFuBao1 zhiFuBao1 = (ZhiFuBao1) new XXBao(zhiFuBao).getProxyInstance();
                //通过接口调用核心方法
                zhiFuBao1.zhuanzhang("张三","李四",8000.0);    
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值