(十)反射

能够分析类能力的程序称为反射。

Class类

程序运行中,系统为每个对象维护一个运行时的类标识,该信息可以追踪对象所属的类。可以通过专门的java类访问这些信息,保存这些信息的类称为Class类。

获取类型标识:

Employee e;

Class c1 = e.getClass();

获取类名对应的Class对象

String className = "java.util.Date";

Class c2 = Class.forName(className);

通过Class类实例化一个对象

e.getClass().newInstance();

将会调用e所属的类的默认构造器。如果需要为构造器提供参数,使用Constructor类的newInstance方法。

虚拟机为每个类管理一个Class对象,因此可以使用==来比较两个Class对象,由此判断两个对象是否属于同一个类

e.getClass()==g.getClass()

注:getClass和instanceof的区别见这里

 

利用反射分析类的能力

检查类的结构

java.lang.reflect包中有三个类Field,Method,Constructor分别描述类的域,方法和构造器。

Class类中的getFields,getMethods,getConstructor方法返回类提供的public域,方法和构造器的数组,包括超类的公有成员。

Class类中的getDeclareFields,getDeclareMethods,getDeclareConstructor返回类中声明的全部域,方法和构造器的数组,包括私有和保护的成员,不包括超类的成员。

 

在运行时使用反射分析对象

除了可以查看类的结构外,还可以查看数据域的实际内容。

查看对象域的关键方法是Field的get方法。如果f是一个Field类型的对象,obj是某个包含f域的类的对象,f.get(obj)将返回一个对象,其值为obj域的当前值。

举例:

Employee harry = new Employee("Harry",3500,10,1,1989);

Class c1 = harry.getClass();

Field f = c1.getDeclaredField("name");

Object v = f.get(harry);

 

使用反射编写泛型数组代码

java.lang.reflect的Array类允许动态创建数组。

Class的getComponentType方法可以获取数组内元素的类型。

下面,我们使用反射编写Arrays的copyOf方法:

以下为该方法的解释

static <T> T[]              copyOf(T[] original, int newLength)

Copies the specified array, truncating or padding with nulls (if necessary) so the copy has the specified length.

该方法将原来的对象数组拷贝到一个新的对象数组中,对象类型不确定。

public static Object copyOf(Object a, int newLength)

首先,我们需要通过Array类的newInstance动态创建一个新的数组,由于数组元素类型不确定,需要使用反射机制获取

Class c1 = a.getClass();

Class componentType = c1.getComponentType();

接着,获取原来的数组长度

int length = Array.getLength(a);

其次,通过componentType和length创建数组对象

Object newArray = Array.newInstance(componentType,length);

最后,执行数组的复制

System.arraycopy(a,0,newArray,Match.min(length,newLength));

完整代码:

public static Object copyOf(Object a, int newLength){
    Class c1 = a.getClass();
    if(!c1.isArray()) return null;
    Class componentType = c1.getComponentType();
    int length = Array.getLength(a);
    Object newArray = Array.newInstance(componentType,length);
    System.arraycopy(a,0,newArray,Match.min(length,newLength));
    return newArray;
}

调用任意方法

Method类的invoke方法,它允许调用包装在当前Method对象中的方法。

比如m1代表Employee类的getName方法,harry是Employee对象:

String n = (String)m1.invoke(harry);

 

详细信息看这里

posted @ 2016-10-14 21:24  且听风吟-wuchao  阅读(139)  评论(0编辑  收藏  举报