按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
是,操作非常简单:
//: MutableInteger。java
// A changeable wrapper class
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);
}
} ///:~
注意n 在这里简化了我们的编码。
若默认的初始化为零已经足够(便不需要构建器),而且不用考虑把它打印出来(便不需要 toString ),那
么 IntValue 甚至还能更加简单。如下所示:
class IntValue { int n; }
将元素取出来,再对其进行造型,这多少显得有些笨拙,但那是Vector 的问题,不是IntValue 的错。
12。4。1 创建只读类
完全可以创建自己的只读类,下面是个简单的例子:
//: Immutable1。java
// Objects that cannot be modified
// are immune to aliasing。
public class Immutable1 {
private int data;
public Immutable1(int initVal) {
data = initVal;
}
public int read() { return data; }
370
…………………………………………………………Page 372……………………………………………………………
public boolean nonzero() { return data != 0; }
public Immutable1 quadruple() {
return new Immutable1(data * 4);
}
static void f(Immutable1 i1) {
Immutable1 quad = i1。quadruple();
System。out。println(〃i1 = 〃 + i1。read());
System。out。println(〃quad = 〃 + quad。read());
}
public static void main(String'' args) {
Immutable1 x = new Immutable1(47);
System。out。println(〃x = 〃 + x。read());
f(x);
System。out。println(〃x = 〃 + x。read());
}
} ///:~
所有数据都设为private,可以看到没有任何public 方法对数据作出修改。事实上,确实需要修改一个对象
的方法是quadruple(),但它的作用是新建一个Immutable1 对象,初始对象则是原封未动的。
方法 f()需要取得一个 Immutable1对象,并对其采取不同的操作,而 main()的输出显示出没有对x 作任何修
改。因此,x 对象可别名处理许多次,不会造成任何伤害,因为根据 Immutable1类的设计,它能保证对象不
被改动。
12。4。2 “一成不变”的弊端
从表面看,不变类的建立似乎是一个好方案。但是,一旦真的需要那种新类型的一个修改的对象,就必须辛
苦地进行新对象的创建工作,同时还有可能涉及更频繁的垃圾收集。对有些类来说,这个问题并不是很大。
但对其他类来说(比如 String 类),这一方案的代价显得太高了。
为解决这个问题,我们可以创建一个“同志”类,并使其能够修改。以后只要涉及大量的修改工作,就可换
为使用能修改的同志类。完事以后,再切换回不可变的类。
因此,上例可改成下面这个样子:
//: Immutable2。java
// A panion 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);
}
}
371
…………………………………………………………Page 373……………………………………………………………
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 的结果),而不是四个。
这一方法特别适合在下述场合应用:
372
…………………………………………………………Page 374……………………………………………………………
(1) 需要不可变的对象,而且
(2) 经常需要进行大量修改,或者
(3) 创建新的不变对象代价太高
12。4。3 不变字串
请观察下述代码:
//: Stringer。java
public class Stringer {
static