clone() 雖能產生本地副本,但程式設計師必須自行防範別名副作用。若提供通用庫無法保證正確克隆,或想保留別名優勢(避免不必要複製)卻避免副作用,該如何處理?
定義特殊類別,無任何方法能改變內部狀態。此類別中別名無害:多處代碼讀取同一物件不會產生副作用。
Java 標準庫提供基本型別「包裝器」類別(Integer、Double 等)即屬此類:
//: ImmutableInteger.java
import java.util.*;
public class ImmutableInteger {
public static void main(String[] args) {
Vector v = new Vector();
for(int i = 0; i < 10; i++)
v.addElement(new Integer(i));
// 但如何修改 Integer 內部的 int?
}
} ///:~
Integer 等包裝器以簡單方式實現不可變性:不提供任何修改物件的方法。
//: MutableInteger.java
import java.util.*;
class IntValue {
int n;
IntValue(int x) { n = x; }
public String toString() { return Integer.toString(n); }
}
public class MutableInteger {
public static void main(String[] args) {
Vector v = new Vector();
for(int i = 0; i < 10; i++)
v.addElement(new IntValue(i));
System.out.println(v);
for(int i = 0; i < v.size(); i++)
((IntValue)v.elementAt(i)).n++;
System.out.println(v);
}
} ///:~
若預設初始化為 0 足夠(無需建構子),且不需列印(無需 toString),IntValue 可極度簡化:
class IntValue { int n; }
從 Vector 取出元素再造型雖顯笨拙,但那是 Vector 的問題,非 IntValue 之過。