下面实例是一个实现了克隆与序列化一体的实体抽象DTO类,可供其类继承。只要继承了该类,子类就会自动具有克隆与序列化的特性,另外该抽象类重写了toString()方法,可以打印自身对象详细信息,子类不必要重写即可使用。
package comm.efin.dto;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import comm.efin.CommException;
import comm.efin.util.LogUtil;
public abstract class AbstractDTO implements Serializable, Cloneable {
/**
* 日志记录器,不需要序列化,所以用transient修饰
*/
private transient LogUtil log = LogUtil.getLogUtil(this.getClass());
/**
* 注:自动的Serializable方法反序列化时不会调用默认构造函数
*/
public AbstractDTO() {
}
/**
* 应用反射机制重写克隆方法,这样子类不必要重写 clone方法就可以实现真真的克隆
*
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
Object cloneObj;
try {
// 首先调用父类(Object)的clone克隆对象
cloneObj = super.clone();
// 再克隆上面cloneObj对象里的所有引用属性
Field[] filedArr = this.getClass().getDeclaredFields();
AccessibleObject.setAccessible(filedArr, true);
for (int i = 0; i < filedArr.length; i++) {
// 如果该属性不能是基本类型,则要进行手工克隆,如果是基本类型数据,
//则在该方法第一行就已复制,无需另外克隆
if (!filedArr[i].getType().isPrimitive()) {
// 获取源对象属性值
Object filedVal = filedArr[i].get(this);
// 如果对象属性实现了Cloneable接口
if (filedVal instanceof Cloneable) {
// 用反射查找colone方法
Method cloneMethod = filedVal.getClass().getDeclaredMethod(
"clone", new Class[] {});//clone方法无参数,所以传递一个空数组
// 调用对象属性clone方法,克隆相应的对象属性
Object cloneObject = cloneMethod.invoke(filedVal, null);//无参,传null即可
// 设置克隆出的对象到克隆对象中
filedArr[i].set(cloneObj, cloneObject);
}// 如果被克隆的对象没有实现克隆方法时,直接实行浅拷贝
else {
/*
* 注:走该分支说明该属性对象没有实现Cloneable,如String、 Integer...之
* 类对象就没有实现克隆,因为这些类是final类且类的内容不可变,所以这一类的类
* 深拷贝也是没有意义。但要注意,如果是自己设计的类,就要考虑是否实现Cloneable
* 与重写clone方法,如果没有这样作,也实行浅拷贝
*/
filedArr[i].set(cloneObj, filedVal);
}
}
}
} catch (Exception e) {
log.error("克隆失败.", e);
throw new CloneNotSupportedException("克隆失败.");
}
return cloneObj;
}
/**
* 应用序列化机制来实现深层克隆 这种实现起来简单,但比用clone方式效率低
*
* @throws CommException
* @throws IOException
*/
public AbstractDTO serialize() throws CommException {
AbstractDTO cloneObj;
try {
// 开缓存
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 序列化操作对象
ObjectOutputStream oos;
oos = new ObjectOutputStream(bos);
// 序列化
oos.writeObject(this);
// 从缓存中读取对象字节流
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
// 反序列化操作对象
ObjectInputStream ois = new ObjectInputStream(bis);
cloneObj = (AbstractDTO) ois.readObject();
} catch (Exception e) {
log.error("序列化过程失败.", e);
throw new CommException("序列化过程失败.", e);
}
return cloneObj;
}
/**
* 通过实现Serializable方式序列化时,添加writeObject来达到可控操作序列化
* 在序列化时会调用此方法来实现序列化操作,自动序列化操作失效
* 供ObjectOutputStream.writeObject()调用
*
* @param objectOutput
* @throws IOException
*/
private void writeObject(ObjectOutputStream objectOutput) throws IOException {
objectOutput.defaultWriteObject();
}
/**
* 在反序列化时会调用此方法来实现反序列化操作,自动反序列化操作失效
* 供ObjectInputStream.readObject()调用
*
* @param objectInput
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream objectInput) throws IOException,
ClassNotFoundException {
objectInput.defaultReadObject();
//在这里我们要为log对象进行初始化,因为LogUtil为被序列化,不然的话会为null
log = LogUtil.getLogUtil(this.getClass());
}
/**
* 应用反射机制打印对象信息
*
* @param obj
* @return
*/
private String toString(Object obj) {
// 如果是空
if (obj == null) {
return "null";
}
Class cl = obj.getClass();
// 如果是字符串直接返回
if (cl == String.class) {
return (String) obj;
}
// 如果是数组
if (cl.isArray()) {
String r = cl.getComponentType().getName().replaceAll("^.+\\.", "") + "[]{";
for (int i = 0; i < Array.getLength(obj); i++) {
if (i > 0) {
r += ", ";
}
Object val = Array.get(obj, i);
// 如果数组里的元素为其本类型时
if (cl.getComponentType().isPrimitive()) {
r += val;
} else {
// 否则递归枚举
r += toString(val);
}
}
return r + "}";
}
String r = cl.getName().replaceAll("^.+\\.", "");
r += "[";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
// 获取对象的所有属性名及值
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
if (!r.endsWith("[")) {
r += ", ";
}
r += f.getName() + "=";
try {
Class t = f.getType();
Object val = f.get(obj);
// 如果是其本类型直接连接
if (t.isPrimitive()) {
r += val;
} else {
// 否则递归枚举
r += toString(val);
}
} catch (Exception e) {
e.printStackTrace();
}
}
r += "]";
return r;
}
/**
* 打印所有属性名及值
*/
public String toString() {
return this.toString(this);
}
/**
* 清除DTO所有属性成员,使各属性值所对应的内存块清零
*
* @param obj
* @return
*/
public Object clear(Object obj) {
try {
Class cl = obj.getClass();
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length; i++) {
Field f = fields[i];
Class t = f.getType();
// 如果是基本类型设置成0
if (t.isPrimitive()) {
f.set(obj, new Byte((byte) 0));
// 否则类对象全设置成null
} else {
f.set(obj, null);
}
}
} catch (Exception e) {
log.error(e);
}
return obj;
}
}