第 10 章 Java 语言的反射机制 ......................................................................................................................................................................................2
10.1 Java Reflection API 简介.......................................................................................2
10.2 在远程方法调用中运用发射机机制....................................................................7
10.3 代理模式 .............................................................................................................10
10.3.1 静态代理类 ..............................................................................................11
10.3.2 动态代理类 ..............................................................................................13
10.3.3 在远程方法调用中运用代理类...............................................................16
10.4
小节
.....................................................................................................................21
PDF created with pdfFactory Pro trial version www.pdffactory.com
第 10 章 Java 语言的反射机制
在
Java
运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任
意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态
调用对象的方法的功能来自于 Java 语言的反射(Reflection)机制。Java 反射机制主要提供
了以下功能:
l 在运行时判断任意一个对象所属的类。
l 在运行时构造任意一个类的对象。
l 在运行时判断任意一个类所具有的成员变量和方法。
l 在运行时调用任意一个对象的方法。
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 对象中的所有属性拷贝到新建的对象中,并将它返回。
PDF created with pdfFactory Pro trial version www.pdffactory.com
这个例子只能复制简单的 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;
PDF created with pdfFactory Pro trial version www.pdffactory.com
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()方法,然后执行这些方法,把原来对象
的属性拷贝到新的对象中:
PDF created with pdfFactory Pro trial version www.pdffactory.com
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);
PDF created with pdfFactory Pro trial version www.pdffactory.com