JAVA中的反射和内省
在JAVA中,反射是极其重要的知识,在后期接触的大量框架的底层都 都运用了反射技术,因此掌握反射技术将帮助我们更好地理解这些框架的原理,以便灵活地掌握框架技术的使用。
1、认识Class类
JAVA反射的源头是class类,若想完成反射,必须了解class类。一般情况下,需要有一个类的完整路径引入后,才能按照固定的格式实例化对象。但是,在java中,允许通过一个类的实例化对象找到一个类的完整信息,这就是class类。
Package …
Class x{ }
Public class GetClassNameDemo{
Public static void main(string [ ] arg){
X x=new X();
System.out.println(x.getClass().getName());
}
通过对象的引用x调用了getClass()方法。
Public final Class <?>getName( )
该方法返回值得类型是Class类。这是因为Java中Object类是所有类的父类。所以,任何类的对象都可以通过调用getClass( )方法转变成Class类型来表示。需要注意的是,在方法中使用了泛型声明,若想避免程序出现警告,可以在泛型中指定操作类型。
Class类表示一个类的本身,通过class可以完整地得到一个类中的结构,包括此类中的方法定义,属性定义等。
方法声明 |
功能描述 |
static class <?> forname (string class name) |
返回与带有给定字符串串地类或接口相关联地class |
Contrutor<?>[ ]getConstrctors() |
返回一个包含某些Constructor对象地数组,这些对象反映此class对象所表示类所有公共地构造方法 |
Field[ ]getDeclaredField(String name) |
返回包含某些Filed对象的数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段,包括公共,保护,默认(包)访问和私有字段,但不包括继承的字段。 |
Field[ ] getFields( ) |
返回包含某些Filed对象的数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段,包括公共,保护,默认(包)访问和私有字段,包括继承的字段。 |
Method[ ] getmethods( ) |
返回一个包含某些Method对象的数组,这些对象反映此class对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些类或接口)的公共成员方法 |
Method getMethod(String name,class<?>… parametheryupes) |
返回一个Method对象,反映此class对象所表示的类或接口的指定公共成员方法 |
Class<?>[ ]getinterfaces( ) |
返回该类所实现的接口的一个数组。确定此对象所表示的类或接口实现的接口 |
sTRING getname( ) |
以String的形式返回此class对象所表示的实体(类、接口、数组类、基本类型或void)名称。 |
Package getPackage( ) |
获取此类的包 |
class<? super t> getSuperclass() |
返回此class所表达的实体(类、接口、基本类型、void)的超类的class |
T newinstance( ) |
创建此Class对象所表示类的一个新实例 |
boolean isArray() |
判定此Class对象是否表示一个数组类 |
上述表,大部分用于获取一个类的结构。
在Class类中没有定义非私有的构造方法。因此不能通过new方法实例化class类的对象。
获取class类的实例由下面三种:
1.通过“对象.getClass( )”方式获取该对象的class实例。
2.通过Class类的静态方法forName( ),用类的全路径名获取一个Class实例
3.通过”类名.class”的方式来后去Class类的实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例。
需要注意的是,通过Class类的forName()方法相比其他两种方法更灵活,其他两种方法都需要一个明确的类。如果一个类的操作不确定时,使用起来可能会受一些限制。但是forName()方法只需要以字符串的方法传入即可,所以它时最常用的。
二、通过反射创建对象。
当使用构造方法创建对象的时候,构造方法可以是有参数也可以是无参数的。同样,通过反射创建对象的方式也有两种,就是调用有参和无参。
1.通过无参构造方法实例化对象:
如果想通过Class()类本身实例化其他类的对象。那么就可以使用newInstance( )方法,但是必须要保证被实例化的类中存在一个无参构造方法。
2.通过有参构造方法实例化对象
当通过有参构造方法实例化对象时,需要分为三个步骤完成
(1)通过class类的getConstructors( )方法取得本类中的全部构造方法。
(2)向构造方法中传递一个对象数组进去,里面包含构造方法中所需的各个参数。
(3)通过Constructor类实例化对象。
需要注意的是,Constructor类表示的是构造方法,该类有很多常用的方法。
Constructor类常用方法
方法声明 |
功能描述 |
Int getModifiers( ) |
获取构造方法的修饰符 |
String getName( ) |
获取构造方法的名称 |
Class<?>[ ] getParameterTypes( ) |
获取构造方法中参数类型 |
T newInstance(Object... initargs) |
向构造方法中传递参数,实例化对象 |
通过代码Class实例取得了Person类中的全部构造方法,并以对象数组的形式返回,Person……用于向构造方法中传递参数,并实例化person对象,由于在Person类中只有一个构造方法,所以直接取出第一个元素即可。
三、通过反射访问属性
通过反射不仅可以创建对象,还可以访问属性。在属性操作中,是通过Filed类实现的。它提供的set( )、get( )方法分别用于设置和获取属性。
需要注意的是,如果访问的属性是私有的,则需要在使用set( )、get( )方法前,使用Filed类的setAccessible( ) 方法将需要操作的属性设置可以被外界访问。
四、通过反射调用方法
当获得某个类对应的Class对象后,就可以通过Class对象的getMethods()方法或getMothod()方法获取全部方法或者指定方法。getMethods()方法和getMethod()方法这两个方法的返回值,分别是Method对象数组,Method对象。每个Method对象都对应一个方法,程序可以通过获取Method对象来调用相对应的方法。在Method里包含一个invoke()方法,该方法的定义具体如下:
Public Object invoke(Object obj,Object... args)
在上述方法定义中,参数obj是该方法最主要的参数,它后面的args是一个相当于数组的可变参数,用来接受传入的实参。
内省:
JDK中提供了一套API专门用于操作java对象的属性,它比反射技术操作更加方便。
一、什么是内省
JDK中提供了一套API用来访问某个属性的getter和setter方法,这就是内省。内省(introspector)是java语言对ajvabean类属性、事件和方法的一种标准处理方式,它的出现有利于操作对象属性,并且可以有效减少代码量。
内省访问JavaBean有两种方法,具体如下:
1.先通过java.beans包下的Introspector类获得JavaBean对象的BeanInfo信息,再通过BeanInfo来获取属性的描述器(PropertyDesriptor),然后通过这个属性描述器就可以获取某个属性对应的getter和setter方法,然后通过反射机制来调用这些方法。
2.直接通过java.beans包下的PropertyDescriptor类来操作Bean对象。
需要先定义一个JavaBean:
三、读取JavaBean的属性
Java的内省可以修改javabean的属性,使用Property-Descriptor类的getWrite
Method()方法就可以获取属性对应的setter方法。再JavaBean中,属性的getter和setter方法是成对出现,因此java的内省也提供了读取JavaBean属性的方法,只要使用PropertyDescriptor类的getReadMethod()方法即可。
首先创建Person类的实例,再通过实例调用setter方法直接为属性赋值,然后通过内省读取设置后的属性值。