java反射总结
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。Java程序中获得Class对象通常有如下三种方式:
1).使用Class类的forName()静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名(必须添加完整的包名)
2).调用某个类的class属性来获取该类对应的Class对象。例如Person.class将会返回Person类对应的
Class对象。
3).调用某个类的getClass()方法,该方法是ng.Object类中的一个方法,所以所有Java对象都可以调用该方法,该方法将会返回该对象所属类对应的Class对象
对于第一种方式和第二种方式都是直接根据类来取得该类的Class对象,但相比之下,第二种方式有如下两种优势:
(1).代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。
(2).程序性能更高,因为这种方式无须调用方法,所以性能更好。
也就是说,大部分时候我们应该使用第二种方式来取得指定类的Class对象,但是如果我们只有一个字符串,如"ng.String",如果需要获取该字符串对应的Class对象,则只能使用第一种方式了,使用Class的forName()方法来获取Class对象时,该方法可能抛出一个ClassNotFoundException异常。
一旦获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。
从Class中获取信息
四个方法用于访问Class对应的类所包含的构造器:
1).Connstructor
2).Constructor>[] getConstructors():返回此Class对象所表示的类的所有public构造器。
3).Constructor
4).Constructor>[] getDeclaredConstructors():返回此Class对象所表示的所有构造器,与构造器的访问级别无关
四个方法用于访问Class对应的类所包含的方法:
1).Method getMethod(String name,Class>...parmeterTypes):返回此Class对象所表示的类的指定的指定的public 方法
2).Method[] getMethod():返回此Class对象所表示的类的所有public 方法。
3).Method getDeclaredMethods(String name,Class>...parameterTypes):返回此Class对象所表示的类的指定方法,与方法的访问级别无关。
4).Method[] getDeclaredMethods():返回此Class对象所表示的类的全部方法,与方法的访问级别无关。
如下四个方法用于访问Class对应的类所包含的属性(Field):
1).Field getField(String name):返回此Class对象所表示的类的指定的public属性(Field)。
2).Field[] getFields():返回此Class对象所表示的类
的所有public属性(Field)。
3).Field getDeclaredFields(String name):返回此Class所表示的类的指定属性(Field),与属性的访问级别无关。
4).Field[] getDeclaredFields(String name):返回此Class所表示的类的全部属性(Field),与属性的访问级别无关。
如下三个方法用于访问Class对应的类上所包含的注释:
1). A getAnnotation(Class annotationClass):试图获取该Class对象所表示类上指定类型的注释;如果该类型的注释不存在则返回null.
2).Annotation[] getAnnotations():返回此元素上存在的所有注释。
3).Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。
如下方法用于访问该Class对象对应类所包含的内部类:
1).Class>[] getDeclaredClasses():返回此Class对象所对应类里包含的全部内部类。
如下方法用于访问该Class对象对应类所在的外部类:
1).Class>[] getDeclaringClass():返回此Class对象所对应类所在的外部类。
如下方法用于访问该Class对象所对应类所继承的父类,所实现的接口等:
1).Class>[] getInterfaces():返回该Class对象对应类所实现的全部接口。
2).int getModifiers():返回此类或接口的所有修饰符。修饰符由public,protected,private,final,static,abstract等对应的常量组成,返回的整数应使用Modifier工具类的方法来解码,才可以获取真实的修饰符。
3).Package getPackage():获取此类的包。
4).String getName():以字符串形式返回此Class对象所表示的类的名称。
5).String getSimpleName():以字符串形式返回此Class对象所表示的类的简称。
6).Class super T> getSuperclass():返回该Class所表示的类的超类对应的Class对象。
除此之外,Class对象还可以调用如下几个判断来判断该类是否为接口,枚举,注释类型等:
1).boolean isAnnotation():返回此Class对象是否表示一个注释类型(由 @interface定义)。
2).boolean isAnnotationPresent(Class extends Annotation> annotationClass):返回此Class对象上是否使用了Annotation注释的修饰符。
3).boolean isAnonymousClass():返回此Class对象是否是一个匿名类。
4).boolean isArray():返回此Class对象是否表示一个数组类。
5).boolean isEnum():返回此Class对象是否表示一个枚举(由enum关键字定义)。
6).boolean isInterface():返回此Class对象是否表示一个接口(使用interface定义)。
7).boolean isInstance(Object obj):判断obj是否是此Class对象的实例,该方法可以完全代替instanceof操作符。
上面的多个getMethod方法和getConstructor多个方法中,都有一个需要传入参数类型为Class>,个数可变的参数,用于获取指定的方法或指定的构造器。关于这个参数的作用,假设某个类内部包含如下三个info方法:
public void info()
public v
oid info(String str)
public void info(String str,Integer num)
这两个同名方法属性重载,它们的方法名相同,但是参数列表不同。在Java语言中要确定一个方法光有方法名是不行的,例如我们指定info方法---实际上可以是上面三个方法中的任意一个!如果需要确定一个方法,应该由方法名和形参列表来确定,但形参名没有任何实际意义,所以只能由形参类型来确定。例如我们想要确定第二个info方法,必须指定方法名是info,形参类型是String.class----因此程序中获取该方法使用如下代码:
//前一个参数指定方法名,后面的个数可变的Class参数指定参数类型列表
clazz.getMethod("info",String.class)
获取第三个info方法,则使用如下代码:
clazz.getMethod("info",String.class,Integer.class)
获取构造器时无须传入构造器名----同一个类的所有构造器的名字都是相同的,所以要确定一个构造器只要指定形参列表即可。
使用反射生成并操作对象:
Class对象可以获得该类里的成分包括方法(由Method对象表示),构造器(由Constructor对象表示),Field(由Field对象表示),这三个类都定义在ng.reflect包下,并实现了ng.reflect.Member接口,程序可以通过Method对象来执行对应的方法,通过Constructor对象来调用对应的构造器创建对象,能通过Field对象直接访问并修改对象的属性值。
创建对象:
通过反射来生成对象有如下两种方式:
1).使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法实际上是利用默认构造器来创建该类的实例。
2).先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择使用某个类的指定构造器来创建实例。
通过第一种方式来创建对象是比较常见的情形,因为在很多Java EE框架中都需要根据配置文件信息来创建Java对象,从配置文件兑取的只是某个类的字符串类名,程序就需要根据字符串来创建对应的实例,就必须使用反射。
如果我们不想利用默认构造器来构建Java对象,而想利用指定的构造器来创建Java对象,则需要利用Constructor对象了,每个Constructor对应一个构造器。为了利用指定构造器来创建Java对象需要如下三步:
1).获取该类的Class对象
2).利用Class对象的getConstructor()方法来获取指定构造器。
3).调用Constructor的newInstance()方法来创建Java对象。
调用方法:
当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或指定方法—
—这两个方法的返回值是Method对象组,或者Method对象。
每个Method对象对应一个方法,获得Method对象后,程序就可以通过该Method来调用对应方法,在Method里包含一个invoke()方法,该方法的签名如下:
1).Object invoke(Object obj,Object...args):该方法中的obj是执行该方法的主调,后面的args是执行该方法的实参。
访问属性值:
通过Class对象的getFields()或getField()方法可以获取该类所包括的全部Field(属性)或指定Field.Field提供了如下两组方法来访问属性:
1).getXxx(Object obj):获取obj对象该Field的属性值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消get后面的Xxx。
2).setXxx(Object obj,Xxx val):将obj对象的该Field设置为val值。此处的Xxx对应8个基本类型,如果该属性的类型是引用类型则取消set后面的Xxx。