java反射机制(1)反射理论基础

本文详细介绍了运行时类型识别(RTTI)的概念及其在Java中的应用,并深入探讨了反射机制的功能与实现,包括如何利用反射获取类信息、实例化对象、调用方法等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      运行时类型识别(Run-time Type Identification,RTTI)主要有两种方式,一种是我们在编译时和运行时已经知道了所有的类型,另外一种是功能强大的“反射”机制。

     要理解RTTI在java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是有“class对象”完成的,它包含了与类有关的信息。类是程序的重要组成部分,每个类都有一个class对象,每当编写并编译了一个新类就会产生一个Class对象,它被保存在一个同名的.class文件中。在运行时,当我们想生成这个类的对象时,运行这个程序的java虚拟机会确认这个类的class对象是否已经加载,如果未加载,JVM就会根据类名查找.class文件,并将其载入,一旦这个类class对象被载入内存,他就被用来创建这个类的所有对象。一般RTTI形式包括三种:

    ①传统的类型转换。由RTTI确保类型转换的正确性,如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常;

    ②通过class对象来获取对象的类型。如Class c = Class.forName(""); Object o = c.newInstance();

    ③通过关键字instanceof或者class.isInstance()方法来确定对象是否属于某个特定类型的实例,准确的说,应该是instanceof/Class.isInstance()可以用来确定对象是否属于某个特定类及其所有类的实例,这和equals()或者==不一样,他们用来比较两个对象是否属于同一个类(==用来比较两个句柄是否指向同一个实例),没有考虑继承关系。

一、什么是反射

       上面有关RTTI部分介绍了java在运行过程中,如何识别一个对象的类型。但前提是这个类型在编译时就必须知道,这样才能使用RTTI来识别。即在编译时,编译器必须知道所有通过RTTI来处理的类。

      使用反射机制可以不受这个限制。反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。

1、反射应用场景

      他主要应用于两种情况:①是“基于构件的编程”,在这种编程方式下,将使用某种基于快速应用开发的应用构件工具类构件项目。这是现在常见的可视化编程方法,通过代表不同组件的图标拖动到图板上来创建程序,然后设置构件的属性值来配置它们。在这里,就要用到反射的机制来检查可用的方法并返回方法名。Java通过JavaBeans提供了基于构件的编程架构。

      ②在运行时获取类的信息的另外一个动机,就是希望能够提供在跨网络的远程平台上创建和运行对象的能力。这被称为远程调用(RMI),它允许一个java程序将对象分布在多台机器上,这种分布能力将帮助开发人员执行一些需要进行大量计算的任务,充分利用计算机资源,提高运行速度。

2、反射机制主要提供的功能

①在运行时判断任意一个对象所属的类。

②在运行时构造任意一个类的对象。

③在运行时判断任意一个类所具有的成员变量和方法。

④在运行时调用任意一个对象的方法。

3、java反射相关的API简介(位于java.lang.reflect包中

①class类---代表一个类;

②Filed类---代表类的成员变量;

③Method类---代表类的方法;

④Constructor类---代表类的方法;

⑤Array类--提供了动态创建数组,以及访问数组的元素的静态方法。在该类中的所有方法都是静态方法。

4、注意:在反射的学习过程中,我们一定要把握一个核心的概念:一切的操作都将使用Object完成,类、数组的应用都可以使用Object进行接收。只有把握了这个概念才能更清楚的掌握反射机制。

       正常情况下如果已经有一个类,则肯定可以通过类创建对象;如果现在要求通过一个对象找到一个类的名称,此时就需要用到反射机制。如果要完成反射操作,则首先应该认识的就是Class类。

二、认识Class类

      在正常情况下,需要有一个类的完成路径引入之后才可以按照固定格式产生实例化对象,但是在java中也允许通过一个实例化对象找到一个类的完整信息,这就是Class类的功能。

     由于任何一个类的根类都是Object,所以通过Object类中的final方法getClass()可以获取到实例对象的Class类信息。本质上Class类就是java反射的源头。反射从程序的运行结果来看也很好理解,即可以通过对象反射求出类的名称,如下图:

      Class本身表示一个类的本身,通过Class可以完整得到一个类中的完整结构,包括类中的方法定义,属性定义等。常用操作如下:

       实际上Class类在开发中最常见的用法就是实例化对象的操作,即可以通过一个给定的字符串(此字符串包含了完整的“包.类”的路径)来实例化一个类的对象。但是需要注意的是,通过Class类使用newInstance()方法实例化其他类的对象时,这些类需要有一个无参构造函数。如果不存在无参构造方法,则不能通过这种方式实例化。

三、Constructor类详解

       如果需要实例化的类没有无参构造函数,是不是就不能通过反射方式实例化呢?答案当然是否定的,虽然通过Class类的newInstance无法完成,但可以通过其他的方式进行实例化操作,只是在操作时需要明确的调用类中的构造方法,并将参数传递进去进行实例化,这就是我们要用到的Constructor类。

      先看一下通过Constructor类实例化步骤:

①通过类Class中的getConstructor()取得本类中的全部构造方法;

②向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数;

③之后通过Constructor实例化对象。

      Constructor类表示的是构造方法,此类常用的方法如下:


 下面我们来看一个实例:


 注意:虽然上面的代码完成了对象的实例化过程,但是比较复杂,所以建议读者最好在类中保留一个无参构造方法;

四、Method类的使用

      通过Class类中的getMethods()方法,返回一个Method类的对象数组。如果想进一步取得方法的具体信息,例如,方法的参数、抛出的异常声明等,则就必须依靠Method类,此类中常用的方法如下:



 下面看一个例子,如何通过Method类,输出类中的方法信息:


 
 从程序的运行结果可以发现,程序不仅将Person类的方法输出,也把从Object类中继承而来的方法同样也进行了输出。

五、Field类详解

      在反射操作中同样也可以取得一个类中全部属性,但是在取得属性时有两种不同的操作,分别是:

①得到实现的接口或父类中的公共属性:public Field[] getFields() throws SecurityException;

②得到本类中的全部属性:public Field[] getDeclaredFields() throws SecurityException;

      以上方法返回的都是Field的数组,每一个Field对象都表示类中的一个属性,而想要取得属性信息,则需要Field类中提交的方法,这些方法如下:


 六、反射的深入研究

      反射除了能够取得一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。

1、通过反射调用类中的方法。如果使用反射调用类中的方法,可以通过Method类完成,操作步骤如下:

①通过Class类的getMethod()方法取得一个Method对象,并设置此方法操作所需的参数类型。

②之后可以使用invoke进行调用,并向方法中传递要设置的参数。

看下面一个完整的例子:


 整个调用的过程,可以通过下面图例详解:


2、调用setter及getter方法。

     在面向对象部分一直强调:类中的属性必须封装,封装后的属性通过setter和getter方法设置和取得,那么在使用反射的调用方法操作中,最重要的是调用类中的setter和getter方法,这一点在java的开发中应用非常广泛。下面是一个例子:


 其中initStr方法,所提供的功能就是把属性的首字母大写。

3、通过反射操作属性

在反射中虽然可以通过使用Method类中的setter和getter方法设置和获取属性,但这样的操作还是很麻烦的,所以在反射中可以通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成属性的设置和获得内容操作。但是在操作前需要注意的是,在类中所有属性都已经设置成私有的访问权限,所以在使用set()和get()方法前,首先使用Field类中的setAccessible(true)方法将需要操作的属性设置成被外部访问。

4、通过反射操作数组

反射机制不仅能在类上使用,还可以在任意的引用数据类型的数据上,当然就包含数组了,即可以通过反射操作数组。可以通过Class类的一下方法取得一个数组的Class对象:public Class<?> getComponentType()在反射包操作中Array类表示一个数组,通过该类取得数组长度,以及其他一些操作内容如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值