`

实用AbstractDTO

    博客分类:
  • Java
F# 
阅读更多

下面实例是一个实现了克隆与序列化一体的实体抽象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;
	}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics