分类: Java
2011-05-17 11:10:39
import java.lang.reflect.Field;
import java.lang.reflect.Method;
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()方法的名字:get+属性名称的第一个字母并转成大小+属性名去掉第一个字母,
// 如属性名称为name,则:get+N+ame
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 });
}
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.getId() + " " + customerCopy.getName()
+ " " + customerCopy.getAge());
}
}
class Customer {
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 中的核心类,它有以下方法
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
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()方法,然后执行这些方法,把原来对象的属性拷贝到新的对象中。
在例程InvokeTester类的main()方法中,运用反射机制调用一个InvokeTester对象的add()和echo()方法
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类型,调用add Method 对象的invoke()方法时,只能传递Integer 类型的参数,并且invoke()方法的返回类型也是Integer 类型,Integer 类是int 基本类型的包装类:
Object result=addMethod.invoke(invokeTester,
new Object[]{new Integer(100),new Integer(200)});
清单3:InvokeTester.java



import java.awt.Button;
public class GetClassDemo {
public static void main(String[] args) throws Exception {
GetClassDemo.f1();
GetClassDemo.f2();
GetClassDemo.f3();
GetClassDemo.f4();
}
/**
* 通过getClass()和getSuperclass()方法
*/
public static void f1() {
Button b = new Button();
Class> c1 = b.getClass();
System.out.println(c1);
Class> c2 = c1.getSuperclass();
System.out.println(c2);
Class> c3 = c2.getSuperclass();
System.out.println(c3);
Class> c4 = c3.getSuperclass();
System.out.println(c4);
System.out.println("------------------------------------------------");
}
/**
* 通过Class.forName()方法
* @throws Exception
*/
public static void f2() throws Exception {
Class> c1 = Class.forName("java.lang.String");
System.out.println(c1);
Class> c2 = Class.forName("java.awt.Button");
System.out.println(c2);
Class> c3 = Class.forName("java.util.LinkedList$Entry");
System.out.println(c3);
// 报空指针异常
// Class> c4 = Class.forName("I");
// System.out.println(c4);
Class> c5 = Class.forName("[I");
System.out.println(c5);
System.out.println("------------------------------------------------");
}
/**
* 通过 .class 属性
* @throws Exception
*/
public static void f3() throws Exception {
Class> c1 = String.class;
System.out.println(c1);
Class> c2 = java.awt.Button.class;
System.out.println(c2);
Class> c3 = int.class;
System.out.println(c3);
Class> c4 = int[].class;
System.out.println(c4);
System.out.println("------------------------------------------------");
}
/**
* 通过 .TYPE 属性
* @throws Exception
*/
public static void f4() throws Exception {
Class> c1 = Boolean.TYPE;
System.out.println(c1);
Class> c2 = Byte.TYPE;
System.out.println(c2);
Class> c3 = Character.TYPE;
System.out.println(c3);
Class> c4 = Short.TYPE;
System.out.println(c4);
Class> c5 = Integer.TYPE;
System.out.println(c5);
Class> c6 = Long.TYPE;
System.out.println(c6);
Class> c7 = Float.TYPE;
System.out.println(c7);
Class> c8 = Double.TYPE;
System.out.println(c8);
Class> c9 = Void.TYPE;
System.out.println(c9);
}
}情况1:类存在不带参数的构造函数
直接使用newInstance()方法
情况2:类不存在不带参数的构造函数
先生成Constructor对象,传入参数类型数组,然后调用此对象的newInstance()方法,同时传入实际参数。
运行时调用方法(methods)
这个动作和上述调用“带参数之构造函数”相当类似。首先准备一个Class[]做为参数类型(本例指定其中一个是String,另一个是
Hashtable),然后以此为自变量调用getMethod(),获得特定的Method
object。接下来准备一个Object[]放置自变量,然后调用上述所得之特定Method object的invoke()。
为什么获得Method object时不需指定回返类型?
因为方法重载(method overloading)机制要求signature必须唯一,而回返类型并非signature的一个成份。换句话说,只要指定了method名称和参数列,就一定指出了一个独一无二的方法(method)。
运行时变更属性(fields)内容
与先前两个动作相比,“变更属性(field)内容”轻松多了,因为它不需要参数和自变量。首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set(),
清单9:RuntimeInvoke.java
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Hashtable;
public class RuntimeInvoke {
public double d;
public String func(String s, Hashtable, ?> ht) {
System.out.println("func invoked");
return s;
}
/**
* 通过反射得到方法
* @throws Exception
*/
public static void f1() throws Exception {
Class> c = Class.forName("com.coderdream.reflection.RuntimeInvoke");
Class>[] ptypes = new Class[2];
ptypes[0] = Class.forName("java.lang.String");
ptypes[1] = Class.forName("java.util.Hashtable");
Method m = c.getMethod("func", ptypes);
RuntimeInvoke obj = new RuntimeInvoke();
Object[] arg = new Object[2];
arg[0] = new String("Hello, world");
arg[1] = null;
Object r = m.invoke(obj, arg);
String rval = (String) r;
System.out.println(rval);
System.out.println("------------------------------------------------");
}
/**
* 通过反射得到属性
* @throws Exception
*/
public static void f2() throws Exception {
Class> c = Class.forName("com.coderdream.reflection.RuntimeInvoke");
Field f = c.getField("d");
RuntimeInvoke obj = new RuntimeInvoke();
System.out.println("d= " + (Double) f.get(obj));
f.set(obj, 12.34);
System.out.println("d= " + obj.d);
}
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
RuntimeInvoke.f1();
RuntimeInvoke.f2();
}
}输出结果: