我们知道拷贝就是生成一个新对象和原对象一模一样,但是拷贝也是分方式和程度的,我们来看一下什么是浅拷贝什么是深拷贝
浅拷贝
在Java中,java.lang.Object类的clone()方法用于克隆(浅拷贝,属性的指向是相同的)。
该方法创建一个对象的副本,并通过逐字段分配在其上对其进行调用并返回该对象的引用。
要实现浅拷贝需要实现Cloneable接口,该接口里面没有任何方法,它指向的是java.lang.Object类的clone()
protected native Object clone() throws CloneNotSupportedException;
它是一个native方法,由C/C++实现
我们看看例子,理解下它为啥叫浅拷贝
首先有一个字典对象类,它实现了克隆的接口
@Data
class Dictionary implements Cloneable {
private String name;
private List<String> words;
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
public static void shallowCopy() {
Dictionary dictionary1 = new Dictionary();
dictionary1.setName("汉语词典");
dictionary1.setWords(new ArrayList<String>() {{
add("你好");
add("浅拷贝");
}});
Dictionary dictionary2 = (Dictionary) dictionary1.clone();
System.out.println(dictionary1 == dictionary2);
dictionary2.getWords().add("新词语");
System.out.println("dictionary1: " + dictionary1.toString());
System.out.println("dictionary2: " + dictionary2.toString());
dictionary1.setName("新名字");
System.out.println("dictionary1: " + dictionary1.toString());
System.out.println("dictionary2: " + dictionary2.toString());
}
运行结果:
false
dictionary1: Dictionary(name=汉语词典, words=[你好, 浅拷贝, 新词语])
dictionary2: Dictionary(name=汉语词典, words=[你好, 浅拷贝, 新词语])
dictionary1: Dictionary(name=新名字, words=[你好, 浅拷贝, 新词语])
dictionary2: Dictionary(name=汉语词典, words=[你好, 浅拷贝, 新词语])
从结果上我们知道dictionary1,dictionary2不是指向的同一个对象,确实创建了两个对象,但是当第二个对象属性被修改时,第一个对象也跟着变了。
验证了我们之前说的浅拷贝,两个对象的属性指向的是堆中相同的对象。
深拷贝
深拷贝相对于浅拷贝来说就是属性也是新的对象,我们可以将对象的每一个属性也实现cloneable接口,就可以达到深拷贝的效果。我们也可以使用序列化反序列化来实现深拷贝。
首先将Dictionary实现Serializable接口
@Data
class Dictionary implements Cloneable, Serializable {
private String name;
private List<String> words;
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
private static void deepCopy() throws IOException, ClassNotFoundException {
Dictionary dictionary1 = new Dictionary();
dictionary1.setName("汉语词典");
dictionary1.setWords(new ArrayList<String>() {{
add("你好");
add("浅拷贝");
}});
Dictionary dictionary2 = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(dictionary1);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);
dictionary2 = (Dictionary) ois.readObject();
// 测试方法没关闭流 实际项目记得关闭流
System.out.println(dictionary1 == dictionary2);
dictionary2.getWords().add("新词语");
System.out.println("dictionary1: " + dictionary1.toString());
System.out.println("dictionary2: " + dictionary2.toString());
}
运行结果
false
dictionary1: Dictionary(name=汉语词典, words=[你好, 深拷贝])
dictionary2: Dictionary(name=汉语词典, words=[你好, 深拷贝, 新词语])
我可以看到不管是对象还是它的属性都是独立的,这就是深拷贝。