從表面看,不變類的建立似乎是一個好方案。但是,一旦真的需要那種新類型的一個修改的對象,就必須辛苦地進行新對象的創建工作,同時還有可能涉及更頻繁的垃圾收集。對有些類來說,這個問題並不是很大。但對其他類來說(比如String類),這一方案的代價顯得太高了。
為解決這個問題,我們可以創建一個“同志”類,並使其能夠修改。以後只要涉及大量的修改工作,就可換為使用能修改的同志類。完事以後,再切換回不可變的類。
因此,上例可改成下面這個樣子:
//: Immutable2.java
// A companion class for making changes
// to immutable objects.
class Mutable {
private int data;
public Mutable(int initVal) {
data = initVal;
}
public Mutable add(int x) {
data += x;
return this;
}
public Mutable multiply(int x) {
data *= x;
return this;
}
public Immutable2 makeImmutable2() {
return new Immutable2(data);
}
}
public class Immutable2 {
private int data;
public Immutable2(int initVal) {
data = initVal;
}
public int read() { return data; }
public boolean nonzero() { return data != 0; }
public Immutable2 add(int x) {
return new Immutable2(data + x);
}
public Immutable2 multiply(int x) {
return new Immutable2(data * x);
}
public Mutable makeMutable() {
return new Mutable(data);
}
public static Immutable2 modify1(Immutable2 y){
Immutable2 val = y.add(12);
val = val.multiply(3);
val = val.add(11);
val = val.multiply(2);
return val;
}
// This produces the same result:
public static Immutable2 modify2(Immutable2 y){
Mutable m = y.makeMutable();
m.add(12).multiply(3).add(11).multiply(2);
return m.makeImmutable2();
}
public static void main(String[] args) {
Immutable2 i2 = new Immutable2(47);
Immutable2 r1 = modify1(i2);
Immutable2 r2 = modify2(i2);
System.out.println("i2 = " + i2.read());
System.out.println("r1 = " + r1.read());
System.out.println("r2 = " + r2.read());
}
} ///:~
和往常一樣,Immutable2包含的方法保留了對象不可變的特征,只要涉及修改,就創建新的對象。完成這些操作的是add()和multiply()方法。同志類叫作Mutable,它也含有add()和multiply()方法。但這些方法能夠修改Mutable對象,而不是新建一個。除此以外,Mutable的一個方法可用它的數據產生一個Immutable2對象,反之亦然。
兩個靜態方法modify1()和modify2()揭示出獲得同樣結果的兩種不同方法。在modify1()中,所有工作都是在Immutable2類中完成的,我們可看到在進程中創建了四個新的Immutable2對象(而且每次重新分配了val,前一個對象就成為垃圾)。
在方法modify2()中,可看到它的第一個行動是獲取Immutable2 y,然後從中生成一個Mutable(類似於前面對clone()的調用,但這一次創建了一個不同類型的對象)。隨後,用Mutable對象進行大量修改操作,同時用不著新建許多對象。最後,它切換回Immutable2。在這裡,我們只創建了兩個新對象(Mutable和Immutable2的結果),而不是四個。
這一方法特別適合在下述場合應用:
(1) 需要不可變的對象,而且
(2) 經常需要進行大量修改,或者
(3) 創建新的不變對象代價太高