單純將 clone() 設為 private 無法禁用複製(衍生類無法縮小存取範圍)。針對類別的複製能力,有六種控制策略:
Object.clone() 對欄位操作合理時適用。Cloneable、覆寫 clone() 呼叫 super.clone()、捕獲所有例外(不拋出)。super.clone()。衍生類若要正常運作需自行實作 Cloneable。Cloneable,覆寫 clone() 拋出 CloneNotSupportedException。衍生類若呼叫 super.clone() 會被阻擋。final,覆寫 clone() 拋出例外。唯一能確保複製被禁止的方法(final 防止繼承繞過)。涉及安全物件或控制實例數量時,另將建構子設為 private 提供特殊工廠方法(如 Singleton 模式)。
//: CheckCloneable.java
class Ordinary {} // 中立
class WrongClone extends Ordinary { // 錯誤示範:覆寫但未實作 Cloneable
public Object clone() throws CloneNotSupportedException {
return super.clone(); // 拋出例外
}
}
class IsCloneable extends Ordinary implements Cloneable { // 標準正確
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class NoMore extends IsCloneable { // 拋出例外關閉複製
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
class TryMore extends NoMore { // 正確呼叫 super.clone() 繼承禁用
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class BackOn extends NoMore { // 繞過禁用:不呼叫 super.clone()
private BackOn duplicate(BackOn b) { return new BackOn(); }
public Object clone() { return duplicate(this); }
}
final class ReallyNoMore extends NoMore {} // final 徹底禁用
public class CheckCloneable {
static Ordinary tryToClone(Ordinary ord) {
String id = ord.getClass().getName();
Ordinary x = null;
if(ord instanceof Cloneable) {
try {
System.out.println("Attempting " + id);
x = (Ordinary)((IsCloneable)ord).clone();
System.out.println("Cloned " + id);
} catch(CloneNotSupportedException e) {
System.out.println("Could not clone " + id);
}
}
return x;
}
public static void main(String[] args) {
Ordinary[] ord = { new IsCloneable(), new WrongClone(),
new NoMore(), new TryMore(), new BackOn(), new ReallyNoMore() };
for(int i = 0; i < ord.length; i++) tryToClone(ord[i]);
}
} ///:~
Attempting IsCloneable Cloned IsCloneable Attempting NoMore Could not clone NoMore Attempting TryMore Could not clone TryMore Attempting BackOn Cloned BackOn Attempting ReallyNoMore Could not clone ReallyNoMore
Cloneable 介面clone()clone() 中呼叫 super.clone()clone() 內捕獲例外