基础概念
不可变类是指其实例不能被修改的类,每个实例中包含的信息都应该在创建该实例的时候就提供,并在对象的整个生命周期(lifetime)内固定不变。其中常用的 String、基本类型包装类、BigInteger和BigDecimal 就是不可变类。
为了使类变成不可变,要遵循下面五条规则:
- 不要提供任何回修改对象状态的方法
- 保证类不会被扩展,即不会有方法重写
- 声明所有的域都为final
- 声明所有的域都为私有
- 确保对于任何可变组件的互斥访问
代码示例
// Immutable complex number class (Pages 81-82)
public final class Complex {
private final double re;
private final double im;
public static final Complex ZERO = new Complex(0, 0);
public static final Complex ONE = new Complex(1, 0);
public static final Complex I = new Complex(0, 1);
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
public double realPart() { return re; }
public double imaginaryPart() { return im; }
public Complex plus(Complex c) {
return new Complex(re + c.re, im + c.im);
}
// Static factory, used in conjunction with private constructor (Page 85)
public static Complex valueOf(double re, double im) {
return new Complex(re, im);
}
public Complex minus(Complex c) {
return new Complex(re - c.re, im - c.im);
}
public Complex times(Complex c) {
return new Complex(re * c.re - im * c.im,
re * c.im + im * c.re);
}
public Complex dividedBy(Complex c) {
double tmp = c.re * c.re + c.im * c.im;
return new Complex((re * c.re + im * c.im) / tmp,
(im * c.re - re * c.im) / tmp);
}
}
我们注意上述类的算数运算都是返回一个新的对象,大多数重要的不可变类都使用了该模式。它被称为函数的方法(functional approach)
优点
- 不变对象比较简单,他只有一种状态,即被创建时的状态
- 不可变对象本质上是线程安全的,它不要求同步
- 不仅可以共享不可变对象,还可以共享它们内部的信息
- 不可拜年对象为其他对象提供了大量的构件
- 不可变对象无偿地提供了失败的原子性
缺点
- 不可变类真正唯一的缺点是,对于每个不同的值都需要一个单独的对象,创建这些对象的代价可能很高。
技巧
可以使用静态工程来代替公有的构造器
public final class Complex {
private final double re;
private final double im;
private Complex(double re, double im) {
this.re = re;
this.im = im;
}
public static Complex valueOf(double re, double im) {
return new Complex(re, im);
}
- 优先使用不可变类,只有当性能确实有要求时才需要为不可变类提供对应的可变类
- 对于可变类,因尽可能限制可变性
- 优先使用private final
- 不要在构造器或者静态工厂之外再提供公有的初始化方法