更多 Java 高級知識方面的文章,請參見文集《Java 高級知識》
首先看下面這一段代碼:
Student s = new Student();
Student s1= s;
- 如果是在 C++ 中,會調(diào)用拷貝構(gòu)造函數(shù),復(fù)制一份新的對象,由
s1
指向該新的對象 - 如果是在 Java 中,
s1
為引用,仍然指向s
的內(nèi)存區(qū)域,即同一份對象
在下面的代碼中:
c1
和 c2
剛開始分別指向兩個不同的對象,c2 = c1;
使得 c2
指向 c1
的對象,因此 c2
原本指向的對象 B 失去引用,會被 GC 回收。
public class Clone_Test {
public static void main(String[] args) {
MyClone c1 = new MyClone("A");
MyClone c2 = new MyClone("B");
// c2 指向 c1 的對象
// c2 原本指向的對象 B 失去引用,會被 GC 回收
c2 = c1;
c2.name = "C";
System.out.println(c1.name); // 輸出 C
System.out.println(c2.name); // 輸出 C
}
}
class MyClone {
public String name;
public MyClone(String name) {
this.name = name;
}
}
Clone 的實現(xiàn)
實現(xiàn) Cloneable
接口,并重寫 clone()
方法。
關(guān)于 Cloneable 接口
-
Cloneable
是一個空接口。并不包含任何方法,更像是一個標(biāo)記。
public interface Cloneable {
}
-
implements Cloneable
指示調(diào)用clone()
方法時可以合法地對該對象進(jìn)行按字段的復(fù)制
A class implements the <code>Cloneable</code> interface to indicate to the clone() method that it is legal for that method to make a field-for-field copy of instances of that class.
- 如果不實現(xiàn)
Cloneable
接口,此時在調(diào)用clone()
方法時,會拋出異常CloneNotSupportedException
關(guān)于 Clone 方法
-
clone()
方法是Object
類中自帶的 native 方法,參見 Java Object 類中有哪些方法 -
clone()
方法默認(rèn)是淺復(fù)制- 對基礎(chǔ)類型有用
- 對引用類型只是復(fù)制引用,不是真正地復(fù)制對象
-
clone()
方法不會調(diào)用構(gòu)造方法 - 幾個基本的比較:
x.clone() == x // false,因為創(chuàng)建出了一個新對象
x.clone().getClass() == x.getClass() // true
x.clone().equals(x) // 一般為false,取決于 clone() 方法的具體實現(xiàn)
例如將上述的代碼重構(gòu)為:
public class Clone_Test {
public static void main(String[] args) {
MyClone c1 = new MyClone("A");
MyClone c2 = new MyClone("B");
// c2 指向一個新對象
// c2 原本指向的對象 B 失去引用,會被 GC 回收
c2 = (MyClone) c1.clone();
c2.name = "C";
System.out.println(c1.name); // 輸出 A
System.out.println(c2.name); // 輸出 C
}
}
class MyClone implements Cloneable {
public String name;
public MyClone(String name) {
this.name = name;
}
public Object clone() {
MyClone c = null;
try {
c = (MyClone) super.clone();
} catch (Exception e) {
}
return c;
}
}
淺拷貝 VS 深拷貝
Object
類中自帶的clone()
方法是淺拷貝,即 field-for-field copy。
如果某個對象中包含一些其他對象,例如 Stream
,淺拷貝只會復(fù)制該 Stream
對象的引用,該 Stream
對象會被兩個對象 c1
和 c2
共享,可能會導(dǎo)致問題。
要想實現(xiàn)深拷貝,即對象中包含的其他對象也會復(fù)制出一份新的對象,可以通過如下方式:
- 需要重寫
clone()
方法,實現(xiàn)深拷貝 - 通過序列化方式
ObjectOutputStream ObjectInputStream
- 通過第三方庫