Immutable Objects 不可变对象

如果一个对象在创建后它的状态不可变那这个对象被认为是不可变的。对于不可变对象的极大信任使它作为一个合理的策略来创建简单信任的代码而被广泛认可。

不可变对象在并发程序中十分有用。因为它们不能改变状态,它们不会在线程争用中毁坏或者在不一致性错误中被观察。

程序通常不情愿使用不可变对象,因为他们担心创建一个新的对象的成本与适当的时候更新一个对象的成本截然相反。创建对象的影响通常被过高评估,会抵消与不可变量有关联的效率。这些由于垃圾收集而减少开销和代码消除,需要它去防止可变对象变坏。

下面的子章节演示了谁的实例是可变的并从它衍生出不可变实例的一课。这样做,它们为这种转换给出了一般的规则并且展示了不可变对象的一些优点。


A Synchronized Class Example ---一个同步类的例子

这个类,SynchronizedRGB,定义了颜色对象。每个对象作为三个整形,表示了基本颜色值和给定颜色名字的字符串。

public class SynchronizedRGB {

// Values must be between 0 and 255.
private int red;
private int green;
private int blue;
private String name;

private void check(int red,
int green,
int blue) {
if (red < 0 || red > 255
|| green < 0 || green > 255
|| blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}

public SynchronizedRGB(int red,
int green,
int blue,
String name) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}

public void set(int red,
int green,
int blue,
String name) {
check(red, green, blue);
synchronized (this) {
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}
}

public synchronized int getRGB() {
return ((red << 16) | (green << 8) | blue);
}

public synchronized String getName() {
return name;
}

public synchronized void invert() {
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
name = "Inverse of " + name;
}
}

SynchronizedRGB 必须小心使用以防在一个不一致状态下被看见。例如,一个线程执行了以下代码:

SynchronizedRGB color =
new SynchronizedRGB(0, 0, 0, "Pitch Black");
...
int myColorInt = color.getRGB(); //Statement 1
String myColorName = color.getName(); //Statement 2


另一个线程在Statement 1之后在Statement 2之前调用了color.set方法,myColorInt 的值将不会与myColorName的值匹配。为避免这种结果,那两个语句必须绑定在一起。

synchronized (color) {
int myColorInt = color.getRGB();
String myColorName = color.getName();
}

这种不一致性仅仅可能发生在可变对象上----对于不可变版本的SynchronizedRGB将不是问题。


A Strategy for Defining Immutable Objects 定义不可变对象的策略

下面的规则定义了一个简单策略来创建不可变对象。不是所有的类按照下面规则表明是不可变的。这也不一定意味着这些规则的制定者是草率的---他们也许有更好的原因相信他们类的实例在构建后从不改变。然而,这样的策略需要复杂的分析并不合适新手。

1。 不要提供setter方法---方法修改字段或者与字段相关联的对象。
2。 是所有字段是final和private
3。 不允许子类重写方法。最简单的方法是这样做用fianl声明类。更复杂方式是使构造方法为私有的并通过工厂方法创建实例。
4.如果字段包含的实例与可变对象关联,不允许这些对象改变。
不提供方法修改可变对象
不共享可变对象的引用。从不保存表面的,可变对象的引用,这些对象将传递给构造函数。如果必须,创建复制,保存复制的引用。相似的,在必要时创建你的内部可变对象的复制以避免在你的方法中返回原始值。

按照下面步骤对SynchronizedRGB 使用这种策略的结果:

1 在这个类中有两个setter方法。第一个,设置,任意转换对象。在这个类中没有可变版本。第二个,转换,通过创建一个新的对象代替修改已经存在的可以适应。
2 所有字段是私有的,进一步用final限制。
3 类自身申明为final
4 只有一个对象与字段关联,那个对象自身是不可变的。因此,没有防范改变”contained“可变对象的状态是没有必要的。

经过这些改变,有了ImmutableRGB:

final public class ImmutableRGB {

// Values must be between 0 and 255.
final private int red;
final private int green;
final private int blue;
final private String name;

private void check(int red,
int green,
int blue) {
if (red < 0 || red > 255
|| green < 0 || green > 255
|| blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}

public ImmutableRGB(int red,
int green,
int blue,
String name) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
this.name = name;
}


public int getRGB() {
return ((red << 16) | (green << 8) | blue);
}

public String getName() {
return name;
}

public ImmutableRGB invert() {
return new ImmutableRGB(255 - red,
255 - green,
255 - blue,
"Inverse of " + name);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值