在开发过程中,可能会遇到我们需要一个和某个对象一样数据,但是不是同一个内存地址的新对象,这个时候就需要用到Clone()了.
不过要注意,Clone()分为浅拷贝和深拷贝.区别在于要拷贝的对象是否有非基本变量
准备复制的对象代码
public class CloneMan {
/**
* @fields id 克隆人id
*/
private int id;
/**
* @fields isM 克隆人性别
*/
private boolean isM;
getter...
setter...
}
CloneMan类只有基本变量类型的成员变量,那么Clone一个,只需要实现Cloneable接口,重写Clone()方法即可
public class CloneMan implements Cloneable{
/**
* @fields id 克隆人id
*/
private int id;
/**
* @fields isM 克隆人性别
*/
private boolean isM;
public CloneMan clone() {
try {
return (CloneMan)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
getter...
setter...
}
通过clone()方法就可以获取到新的CloneMan对象.
但是,如果需要克隆的类的成员变量包括了非基本类型的,如String,那么这种方法就失效了.因为里面的非基本变量类型也需要重写clone()方法,这种方式我觉得太烦了.通过查找资料,我知道一个通过IO流来clone对象的方法,亲测有效
public static Object deepClone(Object obj) {
//将对象写入流中
ByteArrayOutputStream bo = new ByteArrayOutputStream();
try {
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
//将对象从流中读出来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
注意:这里传入的Object要实现可序列化接口Serializable
这里得到的是一个Object对象,可以在获取后进行强转获取到想要的类型,我这里处理的是如果有异常返回的是null,所以获取后要进行一次非空判断.
因为这个是一个通用方法,可以写在IOUtil中公用
补充:2018/06/15
在学习 netty 的时候讲到对象序列化的问题,这里的方法实际是将对象序列化为字节数组,然后又将对象还原的过程。
补充:2018/09/19
又看到一种赋值对象的方法,大体的思想是通过class获取默认构造器,然后用默认构造器构造出实例,然后通过spring框架的属性复制的方法将值复制。所以这个方法依赖spring
public static <T> T objectCopy(Object src, Class<T> dstType) {
T dst;
Constructor<?>[] constructors = dstType.getConstructors();
try {
dst = (T) constructors[0].newInstance();
//这个方法就是依赖spring的beans包
//org.springframework.beans.BeanUtils.copyProperties
copyProperties(src, dst);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(ExceptionUtil.printStackTraceToString(e));
}
return dst;
}