Effective Java 第三版讀書筆記——條款3:使用私有構造器來強制實現不可例項化
阿新 • • 發佈:2018-12-20
偶爾你會想寫一個類,這個類只是一組靜態方法和靜態屬性。 這樣的類獲得了不好的名聲,因為有些人濫用這些類而避免以面向物件的方式思考,但是它們有時候確實有實際的用處:
- 它們可以被用來聚集一組建立在基礎型別或陣列之上的相關方法,例如
java.lang.Math
或java.util.Arrays
。 - 它們也可以用於一組靜態方法,用於實現某個介面的物件,例如
java.util.Collections
。 - 最後,這樣的類可以用於 final 類上的一組方法,因為不能將它們放在子類中。
這樣的實用類(utility classes)是不能被設計為可例項化類的:一個例項是沒有意義的。然而,以下兩種實現不可例項化類的方法都是錯誤
- 不提供顯示構造器。在沒有顯式構造器的情況下,編譯器提供了一個公共的、無參的預設構造器。對於使用者來說,該構造方法與其他構造方法沒有什麼區別。
- 建立抽象類。抽象類可以被子類化,子類可以被例項化。此外,它誤導使用者認為該類是為繼承而設計的(條款 19)。
不過,有一個簡單的方法來確保不可例項化。只有當類不包含顯式構造器時,才會生成一個預設構造器,因此可以通過包含一個私有構造器來實現類的不可例項化:
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}
因為顯式構造器是私有的,所以在該類之外是不可訪問的。這個習慣用法有點違反直覺,好像構造器就是設計成不能呼叫的一樣。因此,添加註釋是種明智的做法。
這種方法還有另一個作用——阻止了類的繼承。所有的構造器都必須顯式或隱式地呼叫父類的構造器,而繼承該類的子類卻沒有可訪問的父類構造器來呼叫。