1.反射机制概述Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。这种
动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
Java 反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中:
Class类:代表一个类。
Field 类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor 类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。[1]
2.动态语言和动态性Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods 的所有信息,并可于运行时改变fields内容或调用methods。
动态语言大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。[1]
3.Class类 Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。[2]
获得Class的对象有三种方法:
1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:
MyObject x;
Class c1 = x.getClass();
2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如:
Class c2=Class.forName("MyObject");
MyObject必须是接口或者类的名字。
3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
Class cl1 = Manager.class;
Class cl2 = int.class;
Class cl3 = Double[].class;
注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。
java.lang.Class类是Reflection API 中的核心类,它有以下方法
getName():获得类的完整名字。
getClassLoader():返回该类的类加载器。
getComponentType():返回表示数组组件类型的 Class。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。
getSuperclass():返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
isArray():判定此 Class 对象是否表示一个数组类。
与属性相关函数 getfield(string name):field
getfields():field[]:获得某个类的所有的公共(public)的字段,包括父类。
getdeclaredfield(string name):field
getdeclaredfields():field[]:获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
与方法相关的函数 getmethod(string name,class... parametertypes):method
getmethods():method[]:获得类的public类型的方法,包括父类。
getdeclaredmethods():method[]:获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
getdeclaredmethod(string name,class ...parametertypes):method:获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
与构造函数相关函数
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
构造函数不能继承,因此你调用getconstructor也只能返回这个类型中定义的所有公有构造函数。
例1:getName()举例 Class> c = Class.forName("java.lang.String");
String name = c.getName();
System.out.println(name);
参见:TestClasForname.java
例2:获取类的属性举例[3]
public class A {
public String a1="a1";
private String a2="a2";
}
public class B extends A {
public String b1="b1";
private String b2="b2";
}
如果利用A的类型类调用getfields,那么会返回a1属性,代码如下:
Class> c = Class.forName("
A");
Field[] fieldNames = c.getFields();
for(int i=0;i
System.out.println(fieldNames[i].toString());
结果:
public java.lang.String A.a1
如果利用B的类型类调用getfields,那么会返回a1和b1属性,代码如下:
Class> c = Class.forName("B");
Field[] fieldNames = c.getFields();
for(int i=0;i
System.out.println(fieldNames[i].toString());
结果:
public java.lang.String B.b1
public java.lang.String A.a1
根据属性名称获取Field
c = Class.forName("A");
Field f = c.getField("a1"); //返回public java.lang.String A.a1
Field f = c.getField("a2"); //出错
Field f = c.getDeclaredField("a2"); //返回private java.lang.String A.a2
参见:TestGetFields.java
例3:获取类的方法举例
public class A {
public String a1="a1";
private String a2="a2";
public void methodA1(){
}
private void methodA2(){
}
}
public class B extends A {
public String b1="b1";
private String b2="b2";
public void methodB1(){
}
private void methodB2(){
}
}
通过getDeclaredMethods(),获取当前类所有方法
Class> c = Class.forName("A");
Method[] array_method = c.getDeclaredMethods();
for(int i=0;i System.out.println(array_method[i].toString());
结果
public void A.methodA1()
private void A.methodA2()
通过getMethods(),获取当前类所有方法(包括父类)
c = Class.forName("A");
array_method = c.getDeclaredMethods();
for(int i=0;i System.out.println(array_method[i].toString());
结果
public void A.methodA1()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
通过指定的函数名,获取方法(不带参数)
c = Class.forName("B");
Class[] argsClass = new Class[]{};
Method m = c.getMethod("methodB1", argsClass );
或 Method m = c.getMethod("methodB1", new Class[]{});
System.out.println(m.toString());
结果
public void B.methodB1()
通过指定的函数名,获取方法(带基本类型参数)
c = Class.forName("B");
Class[] parameterTypes = new Class[] { int.class, int.class };
Method myMethod = c.getMethod("add", parameterTypes);
System.out.println(myMethod.toString());
结果
public int B.add(int,int)
通过指定的函数名,获取方法(参数为数组)
c = Class.forName("B");
parameterTypes = new Class[] {int[].class};
myMethod = c.getMethod("testArray", parameterTypes);
System.out.println(myMethod.toString());
结果
public int B.testArray(int[])
参见:TestGetMothed.java
例4:获取构造函数
Class> c = Class.forName("A");
Constructor[] constructors = c.getConstructors();
for(int i=0;i System.out.println(constructors[i].toString());
结果
public A()
public A(java.lang.String)
参见:TestConstructor.java
4.Field类
gettype():class:获得该属性的类型。
getname():string:获得属性名称。
isaccessible():boolean:判断该属性是否是可以访问的,通常私有和保护的类型都是不可以访问的。
get(object obj):object:获得实例obj的属性值,如果这个属性是非公有的,这里会报IllegalAccessException。
set(objectobj,objectvalue):设置该实例的属性值
setAccessible(booleanflag):设置该属性是否可以访问,如果你调用get和set方法,那么有可能会引发访问权限的错误,这个时候你可以调用setaccessible方法使得该属性可以访问。
例1:将private属性a2设置为可访问,并修改其值
A a=new A();
Field f=A.class.getDeclaredField("a2");
f.setAccessible(true);
System.out.println(f.get(a));
f.set(a,"123456");
System.out.println(f.get(a));
结果
a2
123456
参见:TestField.java
5.Method类
getname():string:获得方法的名字。
getreturntype():class:获得方法的返回值类型。
getparametertypes():class[]:获得方法的参数类型。
isaccessible():boolean:判断该方法是否是可以访问的。
setaccessible(booleanflag):设置该方法是否可以访问。
getexceptiontypes():class[]:获得该方法可能抛出的异常类类型。
invoke(objectobj,object...args):object:调用实例obj的相应方法,其参数由args给定,如果没有参数那么可以什么都不写。
例1:通过invoke调用指定的函数
public int add(int param1, int param2)
{
return param1 + param2;
}
Method addMethod = classType.getMethod("add", new Class[] { int.class, int.class });
Object result = addMethod.invoke(invokeTester, new Object[] { new Integer(100), new Integer(200) });
System.out.println((Integer) result);
参见:InvokeTester.java
总结
1.项目参见:ReflactionProject_20100816.zip
2.开发环境:myeclipse7.5 ,jdk1.6
参考文献
1.Java 反射机制深入研究. http://lavasoft.blog.51cto.com/62575/43218
2.深入研究java.lang.Class类 . http://lavasoft.blog.51cto.com/62575/15433
3.
4.Java反射机制总结(实例分析).http://shiyangxt.javaeye.com/blog/293022
阅读(2726) | 评论(0) | 转发(0) |