不可变类是实例不能被修改的类。每个实例中包含的所有信息都必须在创建该实例的时候就提供,并在对象的整个声明周期内固定不变。例如String、BigInteger和BigDecimal类。不可变类更易于设计、实现和使用。
设计不可变类的原则:
- 不要提供任何修改对象状态的方法
- 保证类不会被扩展
- 使所有域都是final的
- 使所有的域都是私有的
- 确保对于任何可变组件的互斥访问
// Immutable class - pages 76-78
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);
}
public static Complex valueOfPolar(double r, double theta) {
return new Complex(r * Math.cos(theta),
r * Math.sin(theta));
}
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);
// Accessors with no corresponding mutators
public double realPart() { return re; }
public double imaginaryPart() { return im; }
public Complex add(Complex c) {
return new Complex(re + c.re, im + c.im);
}
public Complex subtract(Complex c) {
return new Complex(re - c.re, im - c.im);
}
public Complex multiply(Complex c) {
return new Complex(re * c.re - im * c.im,
re * c.im + im * c.re);
}
public Complex divide(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);
}
@Override public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Complex))
return false;
Complex c = (Complex) o;
// See page 43 to find out why we use compare instead of ==
return Double.compare(re, c.re) == 0 &&
Double.compare(im, c.im) == 0;
}
@Override public int hashCode() {
int result = 17 + hashDouble(re);
result = 31 * result + hashDouble(im);
return result;
}
private int hashDouble(double val) {
long longBits = Double.doubleToLongBits(re);
return (int) (longBits ^ (longBits >>> 32));
}
@Override public String toString() {
return "(" + re + " + " + im + "i)";
}
}
不可变对象本质上是线程安全的,它们不要求同步。所以,不可变对象可以被自由的共享。
不可变对象的缺点是:对于每一个不同的值都需要一个单独的对象。
使类成为不可子类化的另一种方法是将类的构造函数私有化,然后提供静态工厂来产生对象。
// Immutable class with static factories instead of constructors
public 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);
}
// Remainder unchanged
}