黑马程序员技术交流社区
标题:
关于运行时通过反射复制对象
[打印本页]
作者:
黑马刘涛
时间:
2012-8-2 12:54
标题:
关于运行时通过反射复制对象
直接上代码
package com.itcast.test2;
import java.lang.reflect.*;
import com.itcast.test1.Ball;
public class RuntimeClone {
/**
* 运行时复制对象
* 这个方法能够创建一个和参数 object 同样类型的对象,
* 然后把 object 对象中的所有属性拷贝到新建的对象中,
* 并将它返回 ,这个例子只能复制简单的 JavaBean
* @author shandawang
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ball ball = new Ball("basketball",1);
try {
Ball cloneBall = (Ball)runtimeClone(ball);
System.out.println(cloneBall.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
/**
*
* @param obj 要复制的对象
* @param args 构造函数参数列表
* @return 复制后的对象
*/
public static Object runtimeClone(Object obj) throws Exception {
// 获取对象的完整类型
Class<?> classType = obj.getClass();
//System.out.println(classType.getName());
// 使用默认构造方法创建一个实例
/*
* 注意:若Ball类型定义了带参数的构造函数,则JVM不会定义默认构造函数
* 此时必须自定义不带参数的构造函数
*/
Object cloneObj = classType.getConstructor().newInstance();
// 获取被复制对象的所有属性
Field[] fields = classType.getDeclaredFields();
String[] fieldNames = new String[fields.length]; // 属性名数组
for(int i = 0;i < fields.length;i++) {
// 获取属性名,通过反射调用对象的getters,setters
fields[i].setAccessible(true);
fieldNames[i] = fields[i].getName();
// 属性名的首字母大写,获取方法名
String firstUpperCaseLetter = fieldNames[i].substring(0, 1).toUpperCase();
String getterMethodName = "get" + firstUpperCaseLetter +
fieldNames[i].substring(1,fieldNames[i].length()); // get方法名
//System.out.println(getterMethodName);
String setterMethodName = "set" + firstUpperCaseLetter +
fieldNames[i].substring(1,fieldNames[i].length()); // set方法名
//System.out.println(setterMethodName);
Method getterMethod = classType.getMethod(getterMethodName);
Method setterMethod = classType.getMethod(setterMethodName,fields[i].getType());
// 调用原对象的get方法获取指定属性值
Object fieldValue = getterMethod.invoke(obj);
// 调用复制对象的set方法设定指定属性值
setterMethod.invoke(cloneObj,fieldValue);
}
return cloneObj;
}
}
复制代码
package com.itcast.test1;
import java.io.Serializable;
/**
* javabean多用于封装属性,而很少具备某些特定的方法功能。
* 试想,javabean的功能就是传递数据,那么类权限为共有也
* 就不足为奇了。下面是标准javabean要遵守的一些规范:
*1. 类访问权限为公有
*2. 所有属性为私有
*3. 每个字段对外提供setter方法和getter方法
*4. 具备一个无参的构造方法
*/
public class Ball implements Serializable {
//private static final long serialVersionUID = 1L;
/**
* 实现序列化
* 要将某类的对象序列化,则该类必须实现Serializable接口,该接口
* 仅是一个标志,告诉JVM该类的对象可以被序列化。如果某类未实现Serializable接口,
* 则该类对象不能实现序列化。
*/
private String ballName;
private int serialNumber;
public Ball() {}
public Ball(String ballName, int serialNumber) {
super();
this.ballName = ballName;
this.serialNumber = serialNumber;
}
public String getBallName() {
return ballName;
}
public void setBallName(String ballName) {
this.ballName = ballName;
}
public int getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(int serialNumber) {
this.serialNumber = serialNumber;
}
@Override
public String toString() {
return "Ball [ballName=" + ballName + ", serialNumber=" + serialNumber
+ "]";
}
}
复制代码
Ball类是之前序列化和反序列化时实现了serializable接口。现在我要运行时通过反射复制对象,而ball对象里有序列化ID号,获取属性时同时也会获得这个属性。而这不是我希望的(程序不能运行)。当所有属性都是private时,能不能跳过这个序列号属性。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2