不可变类,即实例不能被修改的类,实例中包含的所有信息在对象的生命周期内固定不变。常见的比如String、基本类型的封装类、BigDecimal、BigInteger。
相对与可变类,不可变更易于设计、实现、使用,且更稳定(less PRone to error)更安全。比如,不可变类本质上就是线程安全的,不需要做同步处理,使用起来也非常方便。
设计不可变类,我们有5个原则
以书中代码为例,这是一种典型的不可变类:
public final class Complex { private final double re; private final double im; public Complex(double re, double im) { this.re = re; this.im = im; } // 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)"; }}
鉴于不可变对象本质上就是线程安全的,不可变对象可以自由地进行传递,根本不用考虑在构造器或者getter中进行实例拷贝。但正如上面的代码,使用不可变类的方法改变其自身状态时都要返回一个单独的对象。如果创建对象的开销较大,这将有可能导致性能问题。
站在类提供者的立场上,我们有两种方法可以解决这一问题:
另外,如果因为某种原因不能使用final修饰不可变类,但又不希望被扩展,除了使用final是否还有其他方法。方法就是,使用public static工厂方法取代所有public构造器。比如:
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));}
新闻热点
疑难解答