浅复制与深复制概念
浅复制
被复制对象
的所有变量
都含有与原来的对象
相同的值,而所有的对其他对象的引用
仍然指向原来的对象
。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制
被复制对象
的所有变量
都含有与原来的对象
相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制
把要复制的对象所引用的对象
都复制
了一遍。
Java中的clone()方法
clone方法将对象复制了一份并返回给调用者。一般而言满足以下要求
- 对任何对象x,都有
x.clone() != x
//克隆对象与原对象不是同一个对象 - 对任何对象x,都有
x.clone().getClass() == x.getClass()
//克隆对象与原对象的类型一样 - 如果对象x的
equals
方法定义恰当,那么x.clone().equals(x)
应该成立。
- 对任何对象x,都有
Java中对象的克隆
- 可以使用Object类的clone()方法获得对象的拷贝
- 在子类中覆盖父类的clone()方法,并声明为public
- 在子类中的clone()方法中,调用super.clone()
- 在子类中实现Cloneable接口
Q:为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?
A:在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。Q:Object类的clone()方法是浅复制还是深复制?
A:浅复制深复制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class Student implements Cloneable
{
String name;
int age;
Professor p;
......
public Object clone() {
Student o=null;
try{
o = (Student)super.clone();
} catch(CloneNotSupportedException e) {
System.out.println(e.toString());
}
//对引用的对象也进行复制
o.p = (Professor)p.clone();
return o;
}
}利用
序列化
来做深复制(主要为了避免重写比较复杂对象的深复制clone()方法)
把对象写入到流的过程是序列化,把对象从流中读出来是反序列化。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。1
2
3
4
5
6
7
8
9
10public Object deepClone() {
//将对象写到流里
ByteArrayOutoutStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
//从流里读出来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return(oi.readObject());
}这样做的前提是对象以及对象内部所有引用到的对象都是可序列化的,否则,就需要仔细考察那些不可序列化的对象或属性可否设成
transient
,从而将之排除在复制过程之外。
PS:深拷贝与浅拷贝问题中,会发生深拷贝的有java中的8中基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝。