不可變類,即實例不能被修改的類,實例中包含的所有信息在對象的生命周期內固定不變。常見的比如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));}新聞熱點
疑難解答