理解 clone() 細節後,可建立便利複製的類別提供本地副本:
//: LocalCopy.java
import java.util.*;
class MyObject implements Cloneable {
int i;
MyObject(int ii) { i = ii; }
public Object clone() {
Object o = null;
try { o = super.clone(); }
catch (CloneNotSupportedException e) { System.out.println("MyObject can't clone"); }
return o;
}
public String toString() { return Integer.toString(i); }
}
public class LocalCopy {
// 傳參考:修改外部物件
static MyObject g(MyObject v) { v.i++; return v; }
// 本地副本:clone 後修改不影響原物件
static MyObject f(MyObject v) {
v = (MyObject)v.clone(); // 關鍵:建立本地副本
v.i++;
return v;
}
public static void main(String[] args) {
MyObject a = new MyObject(11);
MyObject b = g(a);
System.out.println(a == b ? "a == b" : "a != b"); // 參考相等
System.out.println("a = " + a); // 12
System.out.println("b = " + b); // 12
MyObject c = new MyObject(47);
MyObject d = f(c);
System.out.println(c == d ? "c == d" : "c != d"); // 參考不等
System.out.println("c = " + c); // 47
System.out.println("d = " + d); // 48
}
} ///:~
clone() 必須為 public 才能被外部呼叫super.clone()(Object 中為 protected,衍生類可存取)Object.clone() 執行前檢查 Cloneable,未實作則拋出 CloneNotSupportedException,故以 try-catch 包裹g():按參考傳遞,修改外部物件,回傳同一參考(a == b 為真)f():v = (MyObject)v.clone() 建立本地副本,修改隔離,回傳新參考(c != d)語句 v = (MyObject)v.clone() 看似怪異,實則合法:參考 v 指向原物件,呼叫 clone() 產生副本,回傳 Object 參考,造型後指派回 v,原參考被覆蓋指向新副本。
==/!= 僅比較參考位址,非物件內容。參考位址相同即視為「等價」,實質檢測「是否因別名指向同一物件」。