Java Reflection API简介

来源:互联网 发布:c 二维数组一行赋值 编辑:程序博客网 时间:2024/05/17 08:44
本章首先介绍了Java Reflection API的用法,然后介绍了一个远程方法调用的例子,在这个例子中客户端能够远程调用服务器端的一个对象的方法。服务器端采用了反射机制提供的动态调用方法的功能,而客户端则采用了反射机制提供的动态代理功能。

在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态 获取类的信息,以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。Java反射机制主要提供了以下功能:

l 在运行时判断任意一个对象所属的类;

l 在运行时构造任意一个类的对象;

l 在运行时判断任意一个类所具有的成员变量和方法;

l 在运行时调用任意一个对象的方法;

l 生成动态代理。

本章首先介绍了Java Reflection API的用法,然后介绍了一个远程方法调用的例子,在这个例子中客户端能够远程调用服务器端的一个对象的方法。服务器端采用了反射机制提供的动态调用方法的功能,而客户端则采用了反射机制提供的动态代理功能。

10.1 Java Reflection API简介

在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。

l Class类:代表一个类。

l Field类:代表类的成员变量(成员变量也称为类的属性)。

l Method类:代表类的方法。

l Constructor类:代表类的构造方法。

l Array类:提供了动态创建数组,以及访问数组元素的静态方法。

如例程10-1所示DumpMethods类演示了Reflection API的基本作用,它读取命令行参数指定的类名,然后打印这个类所具有的方法信息:

例程10-1 DumpMethods.java

import java.lang.reflect.*;

public class DumpMethods {

public static void main(String args[]) throws Exception{

//加载并初始化命令行参数指定的类

Class classType = Class.forName(args[0]);

//获得类的所有方法

Method methods[] = classType.getDeclaredMethods();

for(int i = 0; i < methods.length; i++)

System.out.println(methods[i].toString());

}

}

运行命令“java DumpMethods java.util.Stack”,就会显示java.util.Stack类所具有的方法,程序的打印结果如下:

public synchronized java.lang.Object java.util.Stack.pop()

public java.lang.Object java.util.Stack.push(java.lang.Object)

public boolean java.util.Stack.empty()

public synchronized java.lang.Object java.util.Stack.peek()

public synchronized int java.util.Stack.search(java.lang.Object)

如例程10-2所示ReflectTester类进一步演示了Reflection API的基本使用方法。ReflectTester类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的对象,然后把object对象中的所有属性复制到新建的对象中,并将它返回。

这个例子只能复制简单的JavaBean,假定JavaBean的每个属性都有public类型的getXXX()和setXXX()方法。

例程10-2 ReflectTester.java

import java.lang.reflect.*;

public class ReflectTester {

public Object copy(Object object) throws Exception{

//获得对象的类型

Class classType=object.getClass();

System.out.println("Class:"+classType.getName());

//通过默认构造方法创建一个新的对象

Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});

//获得对象的所有属性

Field fields[]=classType.getDeclaredFields();

for(int i=0; i<fields.length;i++){

Field field=fields[i];

String fieldName=field.getName();

String firstLetter=fieldName.substring(0,1).toUpperCase();

//获得和属性对应的getXXX()方法的名字

String getMethodName="get"+firstLetter+fieldName.substring(1);

//获得和属性对应的setXXX()方法的名字

String setMethodName="set"+firstLetter+fieldName.substring(1);

//获得和属性对应的getXXX()方法

Method getMethod=classType.getMethod(getMethodName,new Class[]{});

//获得和属性对应的setXXX()方法

Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()});

//调用原对象的getXXX()方法

Object value=getMethod.invoke(object,new Object[]{});

System.out.println(fieldName+":"+value);

//调用复制对象的setXXX()方法

etMethod.invoke(objectCopy,new Object[]{value});

}

return objectCopy;

}

public static void main(String[] args) throws Exception{

Customer customer=new Customer("Tom",21);

customer.setId(new Long(1));

Customer customerCopy=(Customer)new ReflectTester().copy(customer);

System.out.println("Copy information:"+customerCopy.getName()+""+

customerCopy.getAge());

}

}

class Customer{ //Customer类是一个JavaBean

private Long id;

private String name;

private int age;

public Customer(){}

public Customer(String name,int age){

this.name=name;

this.age=age;

}

public Long getId(){return id;}

public void setId(Long id){this.id=id;}

public String getName(){return name;}

public void setName(String name){this.name=name;}

public int getAge(){return age;}

public void setAge(int age){this.age=age;}

}

ReflectTester类的copy(Object object)方法依次执行以下步骤。

(1)获得对象的类型:

Class classType=object.getClass();

System.out.println("Class:"+classType.getName());

在java.lang.Object类中定义了getClass()方法,因此对于任意一个Java对象,都可以通过此方法获得对象的类型。Class类是Reflection API中的核心类,它有以下方法。

l getName():获得类的完整名字。

l getFields():获得类的public类型的属性。

l getDeclaredFields():获得类的所有属性。

l getMethods():获得类的public类型的方法。

l getDeclaredMethods():获得类的所有方法。

l getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes参数指定方法的参数类型。

l getConstrutors():获得类的public类型的构造方法。

l getConstrutor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes参数指定构造方法的参数类型。

l newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

(2)通过默认构造方法创建一个新的对象:

Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});

以上代码先调用Class类的getConstructor()方法获得一个Constructor对象,它代表默认的构造方法,然后调用Constructor对象的newInstance()方法构造一个实例。

(3)获得对象的所有属性:

Field fields[]=classType.getDeclaredFields();

Class类的getDeclaredFields()方法返回类的所有属性,包括public、protected、默认和private访问级别的属性。

(4)获得每个属性相应的getXXX()和setXXX()方法,然后执行这些方法,把原来对象的属性复制到新的对象中:

for(int i=0; i<fields.length;i++){

Field field=fields[i];

String fieldName=field.getName();

String firstLetter=fieldName.substring(0,1).toUpperCase();

//获得和属性对应的getXXX()方法的名字

String getMethodName="get"+firstLetter+fieldName.substring(1);

//获得和属性对应的setXXX()方法的名字

String setMethodName="set"+firstLetter+fieldName.substring(1);

//获得和属性对应的getXXX()方法

Method getMethod=classType.getMethod(getMethodName,new Class[]{});

//获得和属性对应的setXXX()方法

Method setMethod=classType.getMethod(setMethodName,new Class[]{field.getType()});

//调用原对象的getXXX()方法

Object value=getMethod.invoke(object,new Object[]{});

System.out.println(fieldName+":"+value);

//调用复制对象的setXXX()方法

setMethod.invoke(objectCopy,new Object[]{value});

}

以上代码假定每个属性都有相应的getXXX()和setXXX()方法,并且在方法名中,“get”和“set”的后面一 个字母为大写。例如,Customer类的name属性对应getName()和setName()方法。Method类的invoke(Object obj,Object args[])方法用于动态执行一个对象的特定方法,它的第一个obj参数指定具有该方法的对象,第二个args参数指定向该方法传递的参数。

如例程10-3所示的InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法。

例程10-3 InvokeTester.java

import java.lang.reflect.*;

public class InvokeTester {

public int add(int param1,int param2){

return param1+param2;

}

public String echo(String msg){

return "echo:"+msg;

}

public static void main(String[] args) throws Exception{

Class classType=InvokeTester.class;

Object invokeTester=classType.newInstance();

//调用InvokeTester对象的add()方法

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对象的echo()方法

Method echoMethod=classType.getMethod("echo",new Class[]{String.class});

result=echoMethod.invoke(invokeTester,new Object[]{"Hello"});

System.out.println((String)result);

}

}

add()方法的两个参数为int类型,获得表示add()方法的Method对象的代码如下:

Method addMethod=classType.getMethod("add",new Class[]{int.class,int.class});

Method类的invoke(Object obj,Object args[])方法接收的参数必须为对象,如果参数为基本类型数据,必须转换为相应的包装类型的对象。invoke()方法的返回值总是对象,如果实际被 调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象,再将其返回。

在本例中,尽管InvokeTester类的add()方法的两个参数及返回值都是int类型,调用addMethod对象 的invoke()方法时,只能传递Integer类型的参数,并且invoke()方法的返回类型也是Integer类型,Integer类是int基 本类型的包装类:

Object result=addMethod.invoke(invokeTester, new Object[]{new Integer(100),new Integer(200)});

System.out.println((Integer)result); //result为Integer类型

java.lang.Array类提供了动态创建和访问数组元素的各种静态方法。如例程10-4所示的ArrayTester1类的main()方法创建了一个长度为10的字符串数组,接着把索引位置为5的元素设为“hello”,然后再读取索引位置为5的元素的值。

例程10-4 ArrayTester1.java

import java.lang.reflect.*;

public class ArrayTester1 {

public static void main(String args[])throws Exception {

Class classType = Class.forName("java.lang.String");

//创建一个长度为10的字符串数组

Object array = Array.newInstance(classType, 10);

//把索引位置为5的元素设为"hello"

Array.set(array, 5, "hello");

//读取索引位置为5的元素的值

String s = (String) Array.get(array, 5);

System.out.println(s);

}

}

如例程10-5所示的ArrayTester2类的main()方法创建了一个5×10×15的整型数组,并把索引位置为[3][5][10]的元素的值为设37。

例程10-5 ArrayTester2.java

import java.lang.reflect.*;

public class ArrayTester2{

public static void main(String args[]) {

int dims[] = new int[]{5, 10, 15};

Object array = Array.newInstance(Integer.TYPE, dims);

//使arrayObj引用array[3]

Object arrayObj = Array.get(array, 3);

Class cls = arrayObj.getClass().getComponentType();

System.out.println(cls);

//使arrayObj引用array[3][5]

arrayObj = Array.get(arrayObj, 5);

//把元素array[3][5][10]设为37

Array.setInt(arrayObj, 10, 37);

int arrayCast[][][] = (int[][][]) array;

System.out.println(arrayCast[3][5][10]);

}

}

原创粉丝点击