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. 代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

原文地址:https://www.cnblogs.com/snyv-nice/p/13778498.html