Jack Frost

深入Java机制(一)–反射机制和动态代理机制

本系列我将会把自己的学习到Java机制的笔记整理一遍,结合各大实例,从反射机制到动态代理到类加载等等……大家看到有错麻烦请指出。今天讲讲反射机制以及动态代理机制(含代理模式、源码阅读以及对比静态代理),而且基本现在的主流框架都应用了反射机制,如spring、MyBatis、Hibernate等等,这就有非常重要的学习意义了。

文章结构:(1)反射机制概述;(2)反射的相关API;(3)反射机制相关问题;(4)基于反射的动态代理机制(源码阅读以及与静态代理对比)


一、反射机制概述:

(1)定义:

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

(2)作用:(相关面试问题在后面罗列)

(一)在运行时判断任意一个对象所属的类;

(二)在运行时构造任意一个类的对象;

(三)在运行时判断任意一个类所具有的成员变量和方法;

(四)在运行时调用任意一个对象的方法;

(五)在运行时创建新类对象

(六)生成动态代理。(这个我们最后谈)

二、反射的相关API:

此API部分以此博客为基本去扩展

(1)通过一个对象获得完整的包名和类名:

(2)实例化Class类对象:

(3)获取一个对象的父类与实现的接口

(4)获取某个类中的全部构造函数,通过反射机制实例化一个类的对象:

先弄个普通实体类

然后再写操作此实体类的

注意 class1.getConstructors()获取的是构造器的栈,就是哪个构造器在前面就丢到cons[]栈底部。上面是无参构造器丢到最底部。

(5)获取某个类的全部属性:(接口和父类的属性以及本类自身的共有属性)

(6)获取某个类的全部方法:包括父类、接口和自身方法(所有权限都可)

(7)通过反射机制调用某个类的方法:

另外我们顺便看下源码了解下getMethod方法

parameterTypes是可变长参数。

(8)通过反射机制操作某个类的属性:

反射机制的例子:

首先我们要明白,编译后就会把泛型给擦除,还原到类与方法本质。

(1)在泛型为Integer的ArrayList中存放一个String类型的对象。

另外我们还要探讨为什么只能传入Object.class

(2)通过反射取得并修改数组的信息:

注意是反射包下面的类

(3)通过反射机制修改数组的大小:

注意是反射包下面的类

(4)利用反射实现spring的注解注入:

1)我们框架使用的注解:本质是这样的

2)这里就是注解管理。包括:注入的方式、注入前的配置解析抽象等等

3)我们实体类的接口:

4)实体类的实现类:

5)服务的实体类:

6)Spring容器:

spring的思想,控制反转-依赖注入,而不是主动申请创建实例。

7)接着就是用那个spring容器了嘛:

当然,这只是个小demo,spring比这个牛逼多了。

三、反射机制的相关问题:

(1)反射的优缺点:

在理解这个前,我们要先理解静态编译和动态编译。

静态编译:在编译时确定类型,绑定对象,即通过

动态编译:运行时确定类型,绑定对象。动态编译最大限度的发挥了java的灵活性,体现了多态的应用,有利于降低类之间的耦合性。

优点:

可以实现动态创建对象和编译,体现出很大的灵活性。

缺点:

对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求,这意味着通信,意味着又要执行多个步骤。

(2)常用到的地方:

1. 观察或操作应用程序的运行时行为。

2. 调试或测试程序,因为可以直接访问方法、构造函数和成员字段。

3. 通过名字调用不知道的方法并使用该信息来创建对象和调用方法。

另外我们要理解一个东西:

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

编译时的类型由声明该对象时使用的类型决定,运行时的类型由实际赋给对象的类型决定:

如果编译时根本无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,此时就必须使用反射

(3)反射的存在是为了什么??

反射是为了能够动态的加载一个类,动态的调用一个方法,动态的访问一个属性等动态要求而设计的。它的出发点就在于JVM会为每个类创建一个java.lang.Class类的实例,通过该对象可以获取这个类的信息,然后通过使用java.lang.reflect包下得API以达到各种动态需求。

(4)Class类的含义和作用是什么?

每一个Class类的对象就代表了一种被加载进入JVM的类,它代表了该类的一种信息映射。开发者可以通过3种途径获取到Class对象。

1)Class的forName()方法的返回值就是Class类型,也就是动态导入类的Class对象的引用。

2)每个类都会有一个名称为Class的静态属性,通过它也是可以获取到Class对象的,示例代码如下:

3)Object类中有一个名为getClass的成员方法,它返回的是对象的运行时类的Class对象。因为Object类是所有类的父类,所以,所有的对象都可以使用该方法得到它运行时类的Class对象,示例代码如下:

四、基于反射的动态代理机制:

(1)理解设计模式之代理模式:

定义:

为其他对象提供一种代理以控制对这个对象的访问。

角色:以打游戏、游戏代练为例子

1. Subject抽象主题角色。是抽象类或接口,是一个最普通的业务类型定义。游戏者接口。

2. RealSubject具体主题角色。被委托角色、被代理角色,业务逻辑的具体执行者。游戏者–这人想找代练。

3. Proxy代理主题角色。委托类、代理类,负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并在真实主题角色处理完毕前后做预处理和善后处理。代练者。

优点:

1.职责清晰。真实的角色就是实现实际的业务逻辑,不必关心其他非本职责的事务。

2. 高扩展性。具体主题角色可能随时发生变化,然而代理类完全可不做任何修改的情况下使用。

缺点:

无法摆脱仅支持interface代理圈子。那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。

DEMO:

代练的帅哥:

调用场景:

(2)动态代理:

其实就是灵活运用代理模式的一种设计。

动态代理主要涉及两个类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class)。

先来看个例子:

(3)动态代理类相关类的源码:

我们入手的话最好按Proxy.newProxyInstance()方法跳进去看。

总体流程:

1)通过实现InvocationHandler接口创建自己的调用处理器 。

2)通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类。就是说指定代理谁。

3)通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型

4)通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入

为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。

生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))。

注意点:

1)Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。

2)Java中,必须通过接口去管理动态代理。

3)对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法,在invoke方法中我们调用委托类的相应方法,并且可以添加自己的处理逻辑。

(4)认知静态代理与动态代理:

静态代理:

若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理。

例子:

通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。

动态代理

代理类在程序运行时创建的代理方式被成为 动态代理。

也就是说,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

对比:

通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。

详情例子请见上面。


好了,深入Java机制(一)–反射机制和动态代理机制讲完了,又是一篇源码机制阅读记录,以后还有内存机制、类加载机制等等这是积累的必经一步,我会继续出这个系列文章,分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!

更多内容,可以访问JackFrost的博客

码字很辛苦,转载请注明来自JackFrost《深入Java机制(一)–反射机制和动态代理机制》

Leave a Reply

Your email address will not be published. Required fields are marked *