基本类型拷贝:
克隆是针对于对象而言的,基本类型(boolean,char,byte,short,float,double.long)已久具备自身克隆的特性.
int x=1;
int y=x;
System.out.println(x);//1
System.out.println(y);//1
y=2;
System.out.println(x);//1
System.out.println(y);//2
引用的拷贝
//引用拷贝
private static void copyReferenceObject(){
Person p = new Person(23, "li");
Person p1 = p;
System.out.println(p);
System.out.println(p1);
}
打印结果,地址指向相同地址
也就是说,二者的引用是同一个对象,并没有创建出一个新的对象。因此要区分引用拷贝和对象拷贝的区别,下面要介绍的就是对象拷贝。
浅拷贝
class Person implements Cloneable{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
/*Person p=null;
try{
p=(Person) super.clone();
}catch (CloneNotSupportedException e) {
}*/
return super.clone();
}
}
深拷贝
如果你的POJO 存在其他自己定义的类型,如上面person类中再加一个student字段,则clone方法需要加上该子类
自身实现clone 方法 你在涉及到使用拷贝的时候一定要注意别的包提供的类是否出现了问题
深拷贝两种方式:
- 实现Cloneable接口,并且重写Object类中的clone()方法
- 实现Serializable接口序列化
1. 实现Cloneable接口
public class Demo implements Cloneable {
private String name;
private String value;
private DemoInternal demoInternal;
/*省略getter和setter方法*/
@Override
public Demo clone() {
Demo demo = null;
try {
demo = (Demo) super.clone(); //浅复制
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
demo.demoInternal = demoInternal.clone(); //深度复制
return demo;
}
}
public class DemoInternal implements Cloneable {
private String internalName;
private String internalValue;
/*省略getter和setter方法*/
@Override
public DemoInternal clone() {
DemoInternal demoInternal = null;
try {
demoInternal = (DemoInternal) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return demoInternal;
}
}
这种方式要手动将其中的类型进行拷贝,如果该类中类过多,会很麻烦需要手动一个个拷
@Override
protected Object clone() {
Person person=null;
try {
person=(Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
person.car=(Car) this.car.clone();
person.home=(Home) this.home.clone();
person.wife=(Wife) this.wife.clone();
return person;
}
2. 实现Serializable接口
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* 通过字节流序列化实现深拷贝,需要深拷贝的对象必须实现Serializable接口
*
* @author Administrator
*/
public class SerializationUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) {
T cloneObj = null;
try {
// 写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
// 分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
// 返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}
上述的两种方式,都是通过一层又一层地深入,实现对象的深度复制。
3.总结
实现深拷贝的方式,三种方法:
- 手动赋值,效率高,但代码过于啰嗦。
- 序列化与反序列化,使用SerializationUtils的clone(Object
obj)方法,要求拷贝的对象实现了Serializable,Map不行,使用HashMap即可。 - 还有一种方法,用fastjson从Object转成json,然后转回object,本质上是反射
private Object deepCopyByJson(Object obj) {
String json = JSON.toJSONString(obj);
return JSON.parseObject(json, Object.class);
}
一半最好用SerializationUtils,性能要求不高的情况下代码简洁也很重要。