zoukankan      html  css  js  c++  java
  • Java反射机制

    反射的概念及作用
    什么是反射?

    Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键(来源于百度)

    JAVA 反射机制是指在运行状态中,

    1. 对于任意一个类,都能够知道这个类的所有属性和方法;

    2. 对于任意一个对象,都能够调用它的任意方法和属性;

    3. 在程序运行过程中,可以操作正在运行的对象

    这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制

    反射机制的作用

    Java反射机制的作用是(百度):1)在运行时判断任意一个对象所属的类。2)在运行时构造任意一个类的对象。3)在运行时判断任意一个类所具有的成员变量和方法。4)在运行时调用任意一个对象的方法

    ​ Class 类与 java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field,Method,Constructor 类 (每个类都实现了 Member 接口)。这些类型的对象是由 JVM 在运行时创建的,用以表示未知类里对应的成员。

    ​ 这样你就可以使用 Constructor 创建新的对象,用 get() 和 set() 方法读取和修改与 Field 对象关联的字段,用 invoke()方法调用与 Method 对象关联的方法。另外,还可以调用 getFields()、getMethods() 和getConstructors() 等便利的方法,以返回表示字段,方法,以及构造器的对象的数组。这样匿名对象的信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

    通过反射查看类信息

    Java 程序中许多对象在运行时都会出现两种类型:编译时类型和运行时类型

    例如:Person p = new Student();

    这行代码将会生成一个变量 p,该变量的编译类型为 Person,但运行时类型为 Student,除此之外,还有更极端的情形,程序在运行时接收到外部传入的一个对象,该对象的编译类型是 Object,但程序又需要调用该对象运行时类型的方法,为了解决这个问题,程序需要在运行时发现对象和类的真实信息,方法有两种:

    第一种是假设在编译和运行时都完全知道类型的具体信息,在这种情况下,我们可以直接先使用instance of 运算符进行判断,再利用强制类型转换将其转换成运行时类型的变量即可

    第二种是编译时根本无法预知该对象和类的信息,程序只依靠运行时信息来发现该对象和类的真实信息,这就必须使用反射

    获取Class对象

    ​ Java中每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过Class对象就可以访问到加载到JVM(Java虚拟机)中的这个类的所有信息,一旦获得某个类所对应的 Class对象之后,程序就可以调用 Class 对象的方法来获得该对象和该类的真实信息了

    Java程序获得Class对象的三种方式:

    1. Class.forName( )方法。该方法需要传入字符串参数,这个字符串参数的值是某个类的类名(必须添加完整包名)

    2. 调用某个类的 class 属性来获取对于的 Class 对象

    3. 调用某个对象(Object)的 getClass 方法。该方法将返回该对象所属类对于的 Class 对象

    public class Demo1 {
          public static void main(String[] args) throws ClassNotFoundException {
              //通过forName方法获取class对象 forName需要抛出一个异常
              Class aClass = Class.forName("com.gxy.java.entity.Student");
              System.out.println("forName方法获取" + aClass);
              //通过class属性获取class对象
              Class<Student> studentClass = Student.class;
              System.out.println("class属性获取" + studentClass);
              //通过某个对象的 getClass 方法获取对应的 Class 对象
              Student stu = new Student();
              Class class2 = stu.getClass();
              System.out.println("某个对象的getClass方法获取" + class2);
          }
      }

    运行结果:

    forName方法获取class com.gxy.java.entity.Student
    class属性获取class com.gxy.java.entity.Student
    某个对象的getClass方法获取class com.gxy.java.entity.Student
    从Class中获取信息

    Class 类提供了大量方法,这些方法可以让我们访问 Class 对象对应类的详细信息

    1. 访问 Class 对应类所包含的构造器(Constructor):

    • Constructor getConstructor(Class...parameterTypes):返回 Class 对象对应类的指定参数的public 构造器。

    • Constructor[] getConstructors():返回 Class 对象对应类的所有 public 构造器。

    • Constructor getDeclaredConstructor(Class...parameterTypes):返回 Class 对象对应类的指定参数的构造器,与构造器访问级别无关。

    • Constructor[] getDeclaredConstructors():返回 Class 对象对应类的所有构造器,与构造器访问级别无关

     import java.lang.reflect.Constructor;
      ​
      public class Person {
          private Person(){
              System.out.println("这是无参构造器");
          }
          public Person(String name){
              System.out.println("这是一个有参构造器");
          }
          public Person(String name,int age){
              System.out.println("这是有参构造器二号");
          }
          public static void main(String[] args) throws NoSuchMethodException {
              //获取class对象
              Class<Person> clazz = Person.class;
              //获取person类的参数类型为String的public构造器
              Constructor<Person> con = clazz.getConstructor(String.class);
              System.out.println("person类的参数类型为String的public构造器是:
    " + con);
              System.out.println("-----------------------------------------");
              //获取person类中所有的public构造器
              Constructor[] persons = clazz.getConstructors();
              //遍历出集合中的所有数据
              for (Constructor c: persons) {
                  System.out.println("person类public构造器是" + c);
              }
              System.out.println("-------------------------------------------");
              //获取person类中的所有构造方法
              Constructor[] cons = clazz.getDeclaredConstructors();
              for (Constructor x: cons) {
                  System.out.println("获取person类中的所有构造方法有" + x);
              }
          }
      }

    运行结果:

     person类的参数类型为String的public构造器是:
      public com.gxy.java.Person(java.lang.String)
      -----------------------------------------
      person类public构造器是public com.gxy.java.Person(java.lang.String,int)
      person类public构造器是public com.gxy.java.Person(java.lang.String)
      -------------------------------------------
      获取person类中的所有构造方法有public com.gxy.java.Person(java.lang.String,int)
      获取person类中的所有构造方法有public com.gxy.java.Person(java.lang.String)
      获取person类中的所有构造方法有private com.gxy.java.Person()

    2. 访问class对应类所包含的方法(Method):

    • Method getMethod(String name, Class... parameterTypes) :返回 Class 对应类的指定 public 方法。

    • Method[] getMethods() :返回 Class 对应类的所有 public 方法。

    • Method getDeclaredMethod(String name, Class... parameterTypes) :返回 Class 对应类的指定方法,与访问级别无关。

    • Method[] getDeclaredMethods() :返回 Class 对应类的所有方法,与访问级别无关。

     import java.lang.reflect.Constructor;
      import java.lang.reflect.Field;
      import java.lang.reflect.Method;
      ​
      public class Student {
          private Student(){
              System.out.println("这是一个无参构造器");
          }
          public Student(String name){
              System.out.println("这是一个有参构造器");
          }
          public void info(){
              System.out.println("执行无参info方法");
          }
          public void info(String name){
              System.out.println("执行有参info方法");
          }
          public static void main(String[] args) throws NoSuchMethodException {
              //获取student类
              Class<Student> student = Student.class;
              //获取类中的所有方法
              Constructor<?>[] students = student.getDeclaredConstructors();
              //遍历方法
              for (Constructor c: students) {
                  System.out.println("Student类中定义的方法有" + c);
              }
              //获取Class对应类指定的public方法
              Method info = student.getMethod("info", String.class);
              System.out.println("student定义了带字符串类型参数的 info 方法:
    " + info);
          }
      }

    运行结果:

    Student类中定义的方法有private com.gxy.java.Student()
      Student类中定义的方法有public com.gxy.java.Student(java.lang.String)
      student定义了带字符串类型参数的 info 方法:
      public void com.gxy.java.Student.info(java.lang.String)

    3. 访问 Class 对应类所包含的字段(Field):

    ➢ Filed getField(String name) :返回 Class 对应类的指定 public 属性。

    ➢ Filed[] getFields() :返回 Class 对应类的所有 public 属性。

    ➢ Field getDeclaredField(String name) :返回 Class 对应类的指定属性,与访问级别无关。

    ➢ Field[] getDeclaredField s() :返回 Class 对应类的所有属性,与访问级别无关

    import lombok.AllArgsConstructor;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      ​
      import java.lang.reflect.Field;
      ​
      @AllArgsConstructor
      @NoArgsConstructor
      @Data
      public class Student {
          private Integer id;
          public String name;
          public static void main(String[] args) throws NoSuchFieldException {
              //获取class类
              Class student = Student.class;
              //获取class对应类中的所有属性返回 与访问级别无关
              Field[] fields = student.getDeclaredFields();
              for (Field f: fields) {
                  System.out.println("student的属性有 " + f);
              }
              //获取class对应类指定的public属性
              Field field = student.getField("name");
              System.out.println("student类中属性为public的为" + field);
              //获取所有属性为public的值
              Field[] fields1 = student.getFields();
              for (Field f1: fields1) {
                  System.out.println("类中属性为public的有" + f1);
              }
              //返回 Class 对应类的指定属性,与访问级别无关
              Field id = student.getDeclaredField("id");
              System.out.println("student类中id的值为" + id);
          }
      }

    4. 访问 Class 对应类所包含的注解(Annotation)

    <A extends Annotation> A getAnnotation(Class<A> annotationClass):试图获取该 Class 对应类指定类型的注解,如果该类型的注解不存在则返回 null。

    ➢ Annotation [] getAnnotations():返回此元素上存在的所有注解。

    ➢ Annotation [] getDeclaredAnnotations():返回直接存在于此元素上的所有注解

    //声明一个简单的controller
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      //告诉编译器忽略指定的警告,不用在编译完成后出现警告信息
      @SuppressWarnings("unchecked")
      @RestController
      public class HelloWordController {
          @RequestMapping("/sayHello")
          public String sayHello(){
              return "欢迎来到Java反射机制的学习";
          }
      }
      
      //test测试类
      package com.gxy.java;
      import org.junit.Test;
      import java.lang.annotation.Annotation;
      ​
      public class Demo2_test {
          //来自junit包 要导入对应的依赖
          @Test
          public void test(){
              //获取到HelloWordController类
              Class hello = HelloWordController.class;
              //获取HelloWordController类在运行时的注解
              Annotation[] annotations = hello.getAnnotations();
              //遍历拿出所有的注解
              for (Annotation a: annotations) {
                  System.out.println("HelloWorldController 类上存在的注解有:" + a);
              }
              //获取 Class 对应类指定类型的注解
              Annotation annotation = hello.getAnnotation(HelloWordController.class);
              System.out.println("HelloWorldController 类 Property 类型的注解是:
    " + annotation);
          }
      }
      /**
      * 上面的程序访问 HelloController 类上存在的所有注解信息时,没有访问到@SuppressWarnings,
      * 因为这个注解并不是运行注解,所以无法通过反射访问
      */

    运行结果:

     HelloWorldController 类上存在的注解有:@org.springframework.stereotype.Controller(value=)
      HelloWorldController 类 Property 类型的注解是:
      null

    5. 访问 Class 对应类所包含的其他成员

    ➢ Class[] getDeclaredClasses():返回 Class 对应类的全部内部类。

    ➢ Class[] getClasses():返回 Class 对应类的全部 public 内部类。

    ➢ Class<?> getDeclaringClass():返回 Class 对应类的外部类。

    ➢ Class[] getInterfaces():返回 Class 对应类所实现的全部接口。

    ➢ int getModifiers():返回 Class 对应类或接口的所有修饰符。修饰符由 public、protected、private、final、static、abstract 等对应的常量组成,返回的整数应使用 Modifier 工具类的方法来解码,才可以获得真实的修饰符。

    ➢ Package getPackage():获取此类的包。

    ➢String getName():返回 Class 对应类的名称。

    ➢ String getSimpleName():返回 Class 对应类的简称。

    ➢ Class<? super T> getSuperClass():返回 Class 对应类的父类的对应 Class 对象。


    使用反射生成对象并操作对象

    Class 对象可以获得该类里包括的方法(Method)、构造器(Constructor)、属性(Field)等成员,这就意味着程序可以通过 Method 对象来执行对应的方法,通过 Constructor 对象来调用对应的构造器创建对象,通过 Field 对象直接访问并修改对象的属性值

    import java.lang.reflect.Constructor;
      ​
      public class Demo3{
          //异常直接抛出顶级父类 不用多次抛出
          public static void main(String[] args) throws Exception {
              Class aClass = Class.forName("java.lang.StringBuffer");
              //获取StringBuffer中带字符串参数的构造器
              Constructor constructor = aClass.getConstructor(String.class);
              //通过构造器的newInstance方法创建对象
              Object instance = constructor.newInstance("这是一个初始化字符");
              System.out.println(instance);
          }
      }

    1. 创建对象

    反射机制生成对象有两种方式:通过第一种方式来创建对象是比较常见的情形,因为在很多 Java EE 框架中都需要根据配置文件信息来创建 Java 对象,从配置文件读取的只是某个类的字符串类名,程序通过反射来创建对应实例

    ​ ➢ 使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,这种方式要求该 Class 对象的对应类有默认构造器,而执行 newInstance()方法时实际上是利用默认构造器来创建该类实例。

    ​ ➢ 先使用 Class 对象获取 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建该Class 对象对应类的实例。通过这种方式可以选择使用某个类的指定构造器来创建实例

    import java.io.FileInputStream;
      import java.text.SimpleDateFormat;
      import java.util.HashMap;
      import java.util.Map;
      import java.util.Properties;
      /**
      * 这个程序根据配置文件调用 Class 对象的 newInstance 方法创建 Java 对象,并将这些对象放入对象池中然  *后根据存入池中的 name 取出对象。这种使用配置文件来配置对象,然后由程序根据配置文件来创建对象的方式
      * 非常有用,鼎鼎大名的 Spring 框架就是采用这种方式大大简化了 JavaEE 应用的开发,当然,Spring 采用的
      *是信息丰富的 XML 配置文件。
       */
      public class ObjectPoolFactory {
          //定义一个map集合
          private Map<String,Object> map = new HashMap<String,Object>();
          //定义一个创建对象的方法,该方法只要传入一个字符串类名,程序可以根据该类名生成 Java 对象
          private Object createObject(String className) throws Exception{
              //根据字符串来获取对应的class对象
              Class aClass = Class.forName(className);
              //使用 aClass 对应类的默认构造器创建实例
              //newInstance依赖于构造方法,没有构造方法不能创建成功
              return aClass.newInstance();
          }
          public void initPool(String fileName){
              // FileInputStream流被称为文件字节输入流
              // 意思指对文件数据以字节的形式进行读取操作如读取图片视频等
              FileInputStream fis = null;
              try {
                  //需要读取文件名称
                  fis = new FileInputStream(fileName);
                  //新建一个Properties 用于读取Java配置文件
                  Properties pro = new Properties();
                  //从输入流中读取属性列表
                  pro.load(fis);
                  for (String name:pro.stringPropertyNames()) {
                      //创建对象并添加到map集合中
                      map.put(name,createObject(pro.getProperty(name)));
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  try {
                      //如果当前的字节流里面存在数据
                      if(fis != null){
                          //关闭这个字节流
                          fis.close();
                      }
                  } catch (Exception e){
                      e.printStackTrace();
                  }
              }
          }
          public Object getObject(String name){
              //从map集合中取出对象
              return map.get(name);
          }
          public static void main(String[] args) {
              //声明一个对象池工厂
              ObjectPoolFactory pool = new ObjectPoolFactory();
              //给出要读取文件的路径
              pool.initPool("src\main\resources\obj.txt");
              //声明要读取配置文件中的属性
              Object a = pool.getObject("a");
              //格式化时间格式
              SimpleDateFormat sdf =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              //输入所读取到的数据
              System.out.println("获取当前时间为:" + sdf.format(a));
          }
      }
    配值文件:
    a = java.util.Date
    b = javax.swing.JFrame

    运行结果:

      获取当前时间为:2020-10-06 15:41:39

    2. 调用方法

    ​ 当获得某个类的 Class 对象后,就可以通过 Class 对象的 getMethods 方法或者 getMethod 方法来获取全部方法(Method 对象数组)或指定方法(Method 对象,获得 Method 对象后,程序就可以通过 Method对象的 invoke()方法调用目标对象的方法

    ​ 下面程序对前面的对象池工厂进行加强,程序允许在配置文件增加配置对象的属性值,对象池工厂会读取该对象的属性值,并利用该对象的 setter 方法为对应属性设置值

    import com.sun.org.apache.xml.internal.utils.ObjectPool;
      ​
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.IOException;
      import java.lang.reflect.Method;
      import java.util.HashMap;
      import java.util.Map;
      import java.util.Properties;
      ​
      //通过反射实现对 Person 类的 setName 方法的调用
      public class ExtendedObjectPoolFactory {
          //初始化一个map集合
          private Map<String,Object> map = new HashMap<String, Object>();
          //从属性文件中初始化properties属性
          Properties config = new Properties();
          //声明一个方法
          public void init(String fileName){
              //初始化FileInputStream变量
              FileInputStream fis = null;
              try {
                  fis = new FileInputStream(fileName);
                  config.load(fis);
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  try {
                      if(fis != null){
                          fis.close();
                      }
                  } catch (Exception e){
                      e.printStackTrace();
                  }
              }
          }
          public Object createObject(String className) throws Exception{
              //根据字符串获取对应class对象
              Class<?> aClass = Class.forName(className);
              //使用默认构造器创建对象
              return aClass.newInstance();
          }
          //根据配置文件初始化对象池
          public void initPool() throws Exception {
              for (String name : config.stringPropertyNames()){
                  //每取出一个属性名-属性值对时,如果属性名中不包含%,就根据属性值创建一个对象
                  if(!name.contains("%")){
                      map.put(name,createObject(config.getProperty(name)));
                  } else {
                      //将配置文件中的属性按照%分割
                      String[] split = name.split("%");
                      //取出要设置属性的目标对象
                      Object target = getObject(split[0]);
                      //设置该属性的对应的setter方法名
                     String setName = "set" + split[1].substring(0,1).toUpperCase()
                                       +split[1].substring(1);
                      //获取target对应的class对象
                      Class<?> targetClass = target.getClass();
                      //获取改属性对应的setter方法
                      Method m = targetClass.getMethod(setName, String.class);
                      //调用 Method 对象的 invoke 方法执行 setter 方法
                      //invoke 的第一个参数表示目标对象,第二个参数表示调用时传入的实参
                      m.invoke(target,config.getProperty(name));
                  }
              }
          }
          public Object getObject(String name) {
              return map.get(name);
          }
          public static void main(String[] args) throws Exception {
              ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();
              epf.init("src\main\resources\object.txt");
              epf.initPool();
              System.out.println("这是一个配置文件" + epf.getObject("a"));
          }
      }
    //测试类
      public class Demo4 {
      ​
          private String name;
          public String getName(){
              return name;
          }
          public void setName(String name) {
              this.name = name;
              System.out.println("setName方法调用了:" + name);
          }
      }
    配置文件:
    #要写自己的测试类所在位置
    a = com.gxy.java.Demo4
    #set the name of a
    a%name = Test Name

    运行结果:

      setName方法调用了:Test Name
    这是一个配置文件com.gxy.java.Demo4@4a574795

    3. 访问属性值

    通过 Class 对象的 getFields()和 getField()方法可以获得该类所包含的全部 Filed 对象数组或指定Filed 对象

    Filed 提供了两种方法来访问属性:

    ​ ➢ getXxx(Object obj):获取 obj 对象的属性值。此处 Xxx 对应 8 个基本类型,如果是 引用类型则取消get 后面的 Xxx。

    ​ ➢ setXxx(Object obj , Xxx val):将 obj 对象的属性值设置成 val。此处 Xxx 表示 8 个基本类型,如果是引用类型则取消 set 后面的 Xxx。

      
    import java.lang.reflect.Field;
      import java.lang.reflect.Method;
      ​
      class User {
          public String name;
          private int age;
          private void print(){
              System.out.println("姓名:"+name+"
    年龄:"+age);
          }
      }
      public class Demo5 {
          public static void main(String[] args) throws Exception {
              //通过User获取对应的Class对象
              Class<User> userClass = User.class;
              //使用反射创建User实例
              User user = userClass.newInstance();
              //获取user类的name
              Field name = userClass.getField("name");
              //通过实例修改
              name.set(user,"莫离欢");
              //获取user类的private属性age
              Field age = userClass.getDeclaredField("age");
              //通过反射访问该属性时取消访问权限检查
              //true是关闭 false是开启,默认是false开启状态
              age.setAccessible(true);
              //设置age属性
              age.set(user,18);
              //获取user类的私有方法print方法
              Method print = userClass.getDeclaredMethod("print");
              //设置通过反射访问该属性时取消权限检查
              print.setAccessible(true);
              //激活方法 -- 类似于打点调用
              //参数:obj给哪个对象激活方法 args:这个方法需要的参数
              print.invoke(user);
          }
      }

    运行结果:

      姓名:莫离欢
      年龄:18
    动态代理

    1. 代理模式

    ​ 代理模式是常用的 java 设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等;代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务

    ​ 比如你要去银行取钱,你就是委托人,你委托银行的雇员(代理人)帮你办理取钱的业务。你和银行雇员的关联关系是:表面上是银行雇员取钱,但实际上是你在取钱,雇员只是为你提供取钱的服务

    2.动态代理

    ​ 在 Java 的 java.lang.reflect 包下提供了一个 Proxy 类和一个 Invocationhandler 接口。这个类和接口是实现动态代理所必须用到的

    1) Invocationhandler 接口:

    ​ 每一个动态代理类都必须要实现 InvocationHandler 接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler这个接口的 invoke 方法来进行调用

      
    Object invoke(Object proxy, Method method, Object[] args)

    参数解析:

    ​ ➢ Object proxy:指被代理的对象

    ​ ➢ Method method:要调用的方法

    ​ ➢ Object[] args:方法调用时所需的实参

    System.out.println("参数一:被指带的对象:" + proxy.getClass()
                         + "
    参数二:调用的方法method" + method.getName()
                         + "
    参数三:所传入的参数args" + args[0]);  
      参数一:被指带的对象:class com.sun.proxy.$Proxy0
      参数二:调用的方法methodpay
      参数三:所传入的参数args大房间

    2) Proxy 类

    ​ Proxy 类提供了一个创建动态代理对象的方法,该方法定义如下:

      
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
                                          InvocationHandler h)

    参数解析:

    ➢ ClassLoader loader:类加载器,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载。

    ➢ Class<?>[] interfaces:代理类要实现的全部接口。

    ➢ InvocationHandler h:表示代理对象要关联的 InvocationHandler 对象。

      Object o = Proxy.newProxyInstance(
                      consumer.getClass().getClassLoader(),//类加载器 ClassLoader loader
                      consumer.getClass().getInterfaces(),//要实现的接口 Class<?>[] interfaces
                      new InvocationHandler()//关联的 InvocationHandler 对象 {
                          @Override
                          public Object invoke(Object proxy, Method method, Object[] args){
                              return null;
                          }
                      }
              );

    租房案例:

    1. 定义一个接口

    public interface ZuFang {
          //付款方法
          String pay(String claim);
      }
    1. 写这个接口的实现类

    package com.gxy.java.dyx;
      ​
      public class Consumer implements ZuFang {
          @Override
          public String pay(String claim) {
              return "完成要求" + claim + "-----付款成功";
          }
      }
    1. 写测试类

    import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      ​
      public class Test {
          public static void main(String[] args) {
              final Consumer consumer = new Consumer();
      ​
              ZuFang o = (ZuFang) Proxy.newProxyInstance(
                      consumer.getClass().getClassLoader(),//类加载器
                      consumer.getClass().getInterfaces(),//接口
                      new InvocationHandler() {
                          @Override
                          public Object invoke(Object proxy, Method method, Object[] args)
                              throws Throwable {
                              
                              System.out.println("我是中介,我可以帮你选房....");
                              Object invoke = method.invoke(consumer, args);
                              System.out.println("房间已按照您的要求" + args[0] + "选择完毕,请付款");
                              return invoke;
                          }
                      }
              );
              System.out.println(o.pay("大房间"));
          }
      }
    本章总结
    1. 反射机制指的是程序在运行时能够获取自身的信息。在 java 中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

    1. 可以实现动态创建对象和编译,体现出很大的灵活性,特别是在 J2EE 的开发中它的灵活性就表现的十分明显,但是对性能有所影响。

    1. 反射机制就是专门帮我们做那些重复的有规则的事情,所以现在很多的自动生成代码的软件就是运用反射机制来完成的。

    1. 代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

  • 相关阅读:
    取石子(二)巴仕博弈+尼姆博弈
    hdu2430Beans(单调队列)
    LCD: 2D-3D匹配算法
    如何选择视觉CV光源颜色
    gpgpu-sim卡分配程序设计实例分析
    PointRCNN: 点云的3D目标生成与检测
    3D点云重建原理及Pytorch实现
    GPU加速计算
    红外传感器技术
    Linux架构思维导图
  • 原文地址:https://www.cnblogs.com/snyv-nice/p/13778498.html
Copyright © 2011-2022 走看看