您的位置:首页 > 编程语言 > Java开发

利用序列化实现深度克隆

2017-04-01 17:24 113 查看
最近发现项目一个BUG,代码如下:

public static Application getPolicyMap(String productKind, Application applicationUnderWriting) {
Application application = new Application();
if (applicationUnderWriting.getPolicyMapKeyResult() != null && applicationUnderWriting.getPolicyMapKeyResult().size() > 0) {
for (PolicyMapKeyBO policyMapKeyBO : applicationUnderWriting.getPolicyMapKeyResult()) {
if (productKind.equals(policyMapKeyBO.getTypeName())) {
application.getPolicyMapKeyResult().add(policyMapKeyBO);
application.getPolicyMapKeyResult().get(0).setTypeCode(Constants.MAINTYPECODE);
}
}
}
}
对以上代码做一下简单介绍:applicationUnderWriting传入的是一个全局变量,application.getPolicyMapKeyResult().add(policyMapKeyBO);此处将policyMapKeyBO的引用指向了application的PolicyMapKeyResult,application.getPolicyMapKeyResult().get(0).setTypeCode(Constants.MAINTYPECODE);然后在此处改变了policyMapKeyBO的TypeCode值,自然就改变了全局变量applicationUnderWriting,从而使后续流程无法进行(此处有业务校验)。

针对此问题,我想到了利用序列化实现深度克隆,有一下两种方法可以实现。

方法一:

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DeepCloneUtils implements Serializable{

/**
*
*/
private static final long serialVersionUID = 3747630134243407984L;
private static final Logger logger = LoggerFactory.getLogger(DeepCloneUtils.class);

@SuppressWarnings("unchecked")
public static <T> T clone(T sourceObj) {
ByteArrayOutputStream byteArrayOutputStream = null;
ObjectOutputStream objectOutputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
ObjectInputStream objectInputStream = null;
try {
// 将sourceObj对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
// 所以利用这个特性可以实现对象的深拷贝
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(sourceObj);
// 将流序列化成对象
byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object targetOjb = objectInputStream.readObject();
return (T) targetOjb;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
byteArrayOutputStream = null;
byteArrayInputStream = null;
if (objectOutputStream != null) {
objectOutputStream.close();
}
if (objectInputStream != null) {
objectInputStream.close();
}
} catch (IOException e) {
logger.error(ExceptionUtil.getErrorMsg(e),e);
}
}
return null;
}
}
使用此方法的前提是,被序列化的对象sourceObj必须是可序列化的,即实现Serializable标识接口。否则会抛出java.io.NotSerializableException异常。
方法二:

/**
* 使用protostuff来进行javabean的序列化
*
*/
public class ProtostuffUtil {

/**
* 序列化
*
* @param obj
* @return
*/
public static <T> byte[] serializer(T obj) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) obj.getClass();
LinkedBuffer buffer = LinkedBuffer
.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema<T> schema = getSchema(clazz);
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
}

/**
* 反序列化
*
* @param data
* @param clazz
* @return
*/
public static <T> T deserializer(byte[] data, Class<T> clazz) {
try {
T obj = objenesis.newInstance(clazz);
Schema<T> schema = getSchema(clazz);
ProtostuffIOUtil.mergeFrom(data, obj, schema);
return obj;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}

}

此方法,被序列化的对象obj在不实现Serializable标识接口的情况下同样可以被序列化。次方法使用protostuff夹包。

最后我们改写代码就达到了目的:

public static Application getPolicyMap(String productKind, Application applicationUnderWriting) {
Application application = new Application();
ApplicationForService applicationForService = new ApplicationForService();
byte [] reqRPUnderWritingByte = ProtostuffUtil.serializer(reqRPUnderWriting);
application = ProtostuffUtil.deserializer(reqRPUnderWritingByte, Application.class);
if (applicationUnderWriting.getPolicyMapKeyResult() != null && applicationUnderWriting.getPolicyMapKeyResult().size() > 0) {
for (PolicyMapKeyBO policyMapKeyBO : applicationUnderWriting.getPolicyMapKeyResult()) {
if (productKind.equals(policyMapKeyBO.getTypeName())) {
application.getPolicyMapKeyResult().add(policyMapKeyBO);
application.getPolicyMapKeyResult().get(0).setTypeCode(Constants.MAINTYPECODE);
}
}
}
}
浅克隆:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深克隆:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐