java反射机制

来源:互联网 发布:泛普软件 编辑:程序博客网 时间:2024/05/22 15:41
 

Java提供了一套机制来动态执行方法和构造方法,以及数组操作等,这套机制就叫——反射;

Class 类

要发现一个具体的类的信息,首先要取得它的Class 对象
如果你有一个 obj 对象,你可以通过下面的方式来取得它的class对象
Class c = obj.getClass();
你可以通过一个class的实例c 取得它的父类
Class sup = c.getSuperclass();
如果你已经知道一个类在编译时候的名字 (比喻说, Button) ,你可以通过下面这样的简单方法取得class对象
Class c = Button.class;
如果你知道一个类在运行期的名字(比喻说,一个String类型变量str),你可以通过下面的方法取得类对象
Class c = Class.forName(str);

取得类的名字

如果你已经有了一个class对象c,你可以通过下面的方法取得类的名字 c.getName()
getName 取得类的全路径名字; 比喻说,
Class c = Button.class;
String s = c.getName();
System.out.println(s);
会输出
java.awt.Button
类 Class 和它的方法都是在 java.lang中,所以不需要使用import使其可用。

取得所有的父类

getSuperclass() 返回一个 Class 对象 (或者 null 如果你在 Object上使用的话,它是没有父类的 )

下面的代码来自Sun的入门指南:

static void printSuperclasses(Object o) {
Class subclass = o.getClass();
Class superclass = subclass.getSuperclass();
while (superclass != null) {
String className = superclass.getName();
System.out.println(className);
subclass = superclass;
superclass = subclass.getSuperclass();
}
}

取得类的修饰符I

Class对象有一个实例方法 getModifiers() ,它返回一个int型的值

为了“解释” int 型的结果,我们要用到Modifier类的一些方法,它们位于 java.lang.reflect, 所以:

import java.lang.reflect.*;

现在我们就可以做下面的事情了:

if (Modifier.isPublic(m)) {
System.out.println("public");
}

取得类的修饰符II

Modifier 包含下面的一些方法 (只列出部分):
public static boolean isAbstract(int)
public static boolean isFinal(int)
public static boolean isInterface(int)
public static boolean isPrivate(int)
public static boolean isProtected(int)
public static boolean isPublic(int)
public static String toString(int)
这会返回一个如下所示的字符串
"public final synchronized strictfp"

取得接口

一个类可以实现0个或多个接口
getInterfaces() 返回一个 Class 对象的数组
这些是类实现的一些接口
下面的代码来自Sun的入门指南:
static void printInterfaceNames(Object o) {
Class c = o.getClass();
Class[ ] theInterfaces = c.getInterfaces();
for (int i = 0; i < theInterfaces.length; i++) {
String interfaceName = theInterfaces[i].getName();
System.out.println(interfaceName);
}
}
注意:零长度数组在Java中是合法的

判断类和接口

Class 类既能代表类也能代表接口
要确定一个给定的 Class 对象 c 是否是一个是接口,可以使用 c.isInterface()
要研究class对象的更多内容的话,你可以使用下面这些方法:
getModifiers()
getFields() // "fields" == "instance variables"
getConstructors()
getMethods()
isArray()

取得字段

public Field[] getFields() throws SecurityException
返回一个public的字段数组 (变量)
数组的长度允许是0
字段的组织顺序没有任何的规则
本身定义的和通过继承的来的变量都被返回,但是不包含 static 变量
public Field getField(String name)
throws NoSuchFieldException, SecurityException
返回指定名称的 public 字段
如果没有直接的字段被发现,那父类或者接口被递归的查询

使用字段 I

如果 f 是 Field 对象, 那么
f.getName() 返回字段的简单的名字
f.getType() 返回字段的类型 (Class)
f.getModifiers() 返回字段的Modifier
f.toString() 返回一个包含了访问修饰符,类型,和全路径字段名字的字符串
例如: public java.lang.String Person.name
f.getDeclaringClass() 返回定义字段的类的 Class 对象

使用字段 II

obj 对象的字段的值可以使用下面的方式进行操作:
boolean f.getBoolean(obj),
int f.getInt(obj),
double f.getDouble(obj),
等等,返回字段的值,假设它是那个类型或者可以扩展成那个型
Object f.get(obj) 返回一个字段的值,假设它是一个对象
void f.set(obj, value),
void f.setBoolean(obj, bool),
void f.setInt(obj, i),
void f.getDouble(obj, d),等等,设置一个字段的值

构造函数

如果 c 是一个构造函数,那么
c.getName() 返回构造函数的名字,与类的名字完全一致
c.getDeclaringClass() 返回构造函数被声明的 Class 对象
c.getModifiers() 返回构造函数的 Modifier
c.getParameterTypes() 返回一个Class 对象数组, 以声明的顺序
c.newInstance(Object[] initargs) 创建被返回一个c类的实例对象
需要使用简单类型的地方会被自动的转换

方法

public Method[] getMethods()
throws SecurityException
返回一个 Method 对象数组
返回的是类或接口的 public 成员方法,同时也包含继承的来的方法
返回的方法没有任何的顺序
public Method getMethod(String name,
Class[] parameterTypes)
throws NoSuchMethodException, SecurityException

Method 中的方法 I

getDeclaringClass()
返回一个Class 对象,它代表了这个Method 对象所被声明的类或接口
getName()
返回代表这个Method 对象的名字,以字符串的方式
getModifiers()
返回代表这个Method 对象的修饰符,以整型的方式
getParameterTypes()
返回这个Method 对象所需要的参数的 Class 对象数组,以声明的顺序出现

Method 中的方法 II

getReturnType()
返回代表这个Method 对象的返回值的一个 Class对象名字
toString()
返回一个代表这个Method 对象的字符串,通常情况下会很长
public Object invoke(Object obj, Object[] args)
在特定的对象上使用特定的参数,执行这个Method对象所代表的方法
个别的参数会被自动转换来实现一些对基本数据类型的需要

数组 I

可以采用下面的方法来判断一个obj 对象是不是一个数组
Class c = obj.getClass();
c.isArray()
要取得这个数组的元素的类型可以使用,
c.getComponentType()
如果c不是一个数组的话会返回一个 null
在java.lang.reflect 包中包含了一个 Array 类,它提供了一些 static 方法来操作数组

数组 II

要创建一个数组,
Array.newInstance(Class componentType, int size)
返回一个新创建的数组Object对象,
你可以把它造型成你想要的类型
componentType 本身就可以是一个数组
这会产生一个多维数组
维数的最大限制一般在255
Array.newInstance(Class componentType, int[] size)
返回一个新创建的多维数组Object对象 (使用 size.length 维度)

数组 III

得到数组元素的值
Array.get(Object array, int index) 返回一个 Object
Array.getBoolean(Object array, int index) 返回一个 boolean
Array.getByte(Object array, int index) 返回一个 byte
等等.
往数组中保存值,
Array.set(Object array, int index, Object value)
Array.setBoolean(Object array, int index, boolean z)
Array.setByte(Object array, int index, byte b)
等等.

实例 II

1. 得到某个对象的属性

public Object getProperty(Object owner, String fieldName) throws Exception {
Class ownerClass = owner.getClass();

Field field = ownerClass.getField(fieldName);

Object property = field.get(owner);

return property;
}

Class ownerClass = owner.getClass():得到该对象的Class。

Field field = ownerClass.getField(fieldName):通过Class得到类声明的属性。

Object property = field.get(owner):通过对象得到该属性的实例,如果这个属性是非公有的,这里会报IllegalAccessException。

2. 得到某个类的静态属性

public Object getStaticProperty(String className, String fieldName)
throws Exception {
Class ownerClass = Class.forName(className);

Field field = ownerClass.getField(fieldName);

Object property = field.get(ownerClass);

return property;
}

Class ownerClass = Class.forName(className) :首先得到这个类的Class。

Field field = ownerClass.getField(fieldName):和上面一样,通过Class得到类声明的属性。

Object property = field.get(ownerClass) :这里和上面有些不同,因为该属性是静态的,所以直接从类的Class里取。


3. 执行某对象的方法

public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
Class ownerClass = owner.getClass();
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(owner, args);
}
Class owner_class = owner.getClass() :首先还是必须得到这个对象的Class。

3~6行:配置参数的Class数组,作为寻找Method的条件。

Method method = ownerClass.getMethod(methodName, argsClass):通过Method名和参数的Class数组得到要执行的Method。

method.invoke(owner, args):执行该Method,invoke方法的参数是执行这个方法的对象,和参数数组。返回值是Object,也既是该方法的返回值。


4. 执行某个类的静态方法

public Object invokeStaticMethod(String className, String methodName,
Object[] args) throws Exception {
Class ownerClass = Class.forName(className);

Class[] argsClass = new Class[args.length];

for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}

Method method = ownerClass.getMethod(methodName, argsClass);

return method.invoke(null, args);
}
基本的原理和实例3相同,不同点是最后一行,invoke的一个参数是null,因为这是静态方法,不需要借助实例运行。

5. 新建实例

public Object newInstance(String className, Object[] args) throws Exception {
Class newoneClass = Class.forName(className);

Class[] argsClass = new Class[args.length];

for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}

Constructor cons = newoneClass.getConstructor(argsClass);

return cons.newInstance(args);

}
这里说的方法是执行带参数的构造函数来新建实例的方法。如果不需要参数,可以直接使用newoneClass.newInstance()来实现。

Class newoneClass = Class.forName(className):第一步,得到要构造的实例的Class。

第6~第10行:得到参数的Class数组。

Constructor cons = newoneClass.getConstructor(argsClass):得到构造子。

cons.newInstance(args):新建实例。


6. 判断是否为某个类的实例

public boolean isInstance(Object obj, Class cls) {
return cls.isInstance(obj);
}

7. 得到数组中的某个元素

public Object getByArray(Object array, int index) {
return Array.get(array,index);
}