使用反射生成并操作对象

Class 对象可以获得该类里的方法(由 Method 对象表示)、构造器(由 Constructor 对象表示)、成员变量(由 Field 对象表示),这三个类都位于 java.lang.reflect 包下,并实现了 java.lang.reflect.Member 接口。程序可以通过 Method 对象来执行对应的方法,通过 Constructor 对象来调用对应的构造器创建实例,能通过 Field 对象直接访问并修改对象的成员变量值。

本文包含:

  1. 创建对象
  2. 调用方法
  3. 访问成员变量值
  4. 操作数组
  5. 使用反射生成 JDK 动态代理

1. 创建对象

通过反射来生成对象有如下两种方式:
在这里插入图片描述
在这里插入图片描述
如果不想利用默认构造器来创建 Java 对象,而想利用指定的构造器来创建 Java 对象,则需要利用 Constructor 对象,每个 Constructor 对应一个构造器。为了利用指定的构造器来创建 Java 对象,需要如下三个步骤:
在这里插入图片描述
下面程序利用反射来创建一个 JFrame 对象,而且使用指定的构造器。
在这里插入图片描述在这里插入图片描述

2. 调用方法


下面程序对前面的对象池工厂进行加强,允许在配置文件中增加配置对象的成员变量的值,对象池工厂会读取为该对象配置的成员变量值,并利用该对象对应的 setter 方法设置成员变量的值。
在这里插入图片描述在这里插入图片描述
上面程序中 initProperty() 方法里的第一行粗体字代码获取目标类包含一个 String 参数的 setter 方法,第二行粗体字代码通过 Method 的 invoke() 方法来执行该 setter 方法,该方法执行完成后,就相当于执行了目标对象的 setter 方法
在这里插入图片描述
在这里插入图片描述
Spring 框架就是通过这种方式将成员变量值以及依赖对象等都放在配置文件中进行管理的,从而实现较好的解耦。这也是 Spring 框架的 IoC 的秘密。
在这里插入图片描述
实际上,setAccessible() 方法并不属于 Method,而是属于它的父类 AccessbleObject。 因此 Method 、Constructor、Field 都可调用该方法,从而实现通过反射来调用 private 方法、private 构造器和 private 成员变量。即它们可以通过调用该方法来取消访问权限检查,通过反射即可访问 private 成员。

3. 访问成员变量值

通过 Class 对象的 getFields() 或 getField() 方法可以获取该类所包含的全部成员变量或指定成员变量。Field 提供了如下两组方法来读取或设置成员变量的值。
在这里插入图片描述
使用这两个方法可以随意访问指定对象的所有成员变量,包括 private 修饰的成员变量。

4. 操作数组

在 java.lang.reflect 包下还提供了一个 Array 类,Array 对象可以代表所有的数组。程序可以通过使用 Array 来动态地创建数组,操作数组元素等。
Array 提供了如下几个类方法:
在这里插入图片描述
下面程序示范了如何使用 Array 来生成数组,为指定元素赋值,并获得指定数组元素的方式。
在这里插入图片描述在这里插入图片描述

5. 使用反射生成 JDK 动态代理

在 Java 的 java.lang.reflect 包下提供了一个 Proxy 类和一个 Invocationhandler 接口,通过使用这个类和接口可以生成 JDK 动态代理类或者动态代理对象。

  1. 使用 Proxy 和 InvocationHandler 创建动态代理
    Proxy 提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态的生成实现类,就可以使用 Proxy 来创建动态代理类:如果需要为一个或多个接口动态地创建实例,也可以使用 Proxy 来创建动态代理实例。

Proxy 提供了如下两个方法来创建动态代理类和动态代理实例。
在这里插入图片描述
在这里插入图片描述
当程序使用反射方式为指定接口生成系列动态代理对象时,这些动态代理对象的实现类实现了一个或多个接口。动态代理对象就需要实现一个或多个接口里定义的方法,但问题是:系统怎么知道如何实现这些方法?这个时候就轮到 InvocationHandler 对象登场了----当执行动态代理对象里的方法时,实际上会替换成调用 InvocationHandler 对象的 invoke 方法。

程序中可以采用先生成一个动态代理类,然后通过动态代理来创建代理对象的方式生成一个动态代理对象。
在这里插入图片描述
上面代码也可以简化成如下代码:
在这里插入图片描述
下面程序示范了使用 Proxy 和 InvocationHandler 来生成动态代理对象。
在这里插入图片描述在这里插入图片描述
上面程序首先提供了一个Person 接口,该接口包含 walk() 和 sayHello() 两个抽象方法,接着定义一个简单的 InvocationHandler 实现类,定义该实现类时需要重写 invoke() 方法----调用代理对象的所有方法时都会被替换成调用该 invoke() 方法。
该 invoke() 方法中的三个参数解释如下:
在这里插入图片描述
上面程序中第一行粗体字代码创建了一个 InvocationHandler 对象,第二行粗体字代码根据 InvocationHandler 对象创建了一个动态代理对象。运行上面程序,结果如下:
在这里插入图片描述
从上图可以看出,不管程序是执行代理对象的walk() 方法,还是执行代理对象的 sayHello() 方法,实际上都是执行 InvocationHandler 对象的 invoke() 方法。

  1. 动态代理和 AOP
    由于 JDK 动态代理只能为接口创建动态代理,所以下面先提供一个 Dog 接口,该接口代码非常简单,仅仅在该接口里定义了两个方法。在这里插入图片描述
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
    借助于 Proxy 和 InvocationHandler 就可以实现
    在这里插入图片描述
    下面再为程序提供一个 MyProxyFactory 类,该对象专为指定的 target 生成动态代理实例。
    在这里插入图片描述在这里插入图片描述
    下面提高一个主程序来测试这种动态代理的效果。
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    AOP 代理包含的方法与目标对象包含的方法示意图如下图所示:
    在这里插入图片描述
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值