Tips
《Effective Java, Third Edition》一書英文版已經出版,這本書的第二版想必很多人都讀過,號稱Java四大名著之一,不過第二版2009年出版,到現在已經將近8年的時間,但隨着Java 6,7,8,甚至9的發布,Java語言發生了深刻的變化。
在這里第一時間翻譯成中文版。供大家學習分享之用。
4. 使用私有構造方法執行非實例化
偶爾你會想寫一個類,它只是一組靜態方法和靜態屬性。 這樣的類獲得了不好的名聲,因為有些人濫用這些類而避免以面向對象方式思考,但是它們確實有着特殊的用途。 它們可以用來按照java.lang.Math
或java.util.Arrays
的方式,在基本類型的數值或數組上組織相關的方法。 它們也可以用於將靜態方法(包括工廠(條目 1))分組,用於實現某個接口的對象,其方式為java.util.Collections
。 (從Java 8開始,你也可以將這些方法放在接口中,假如它是你自己修改的。)最后,這樣的類可以用於在final類上對方法進行分組,因為不能將它們放在子類中。
這樣的實用類( utility classes)不是設計用來被實例化的:一個實例是沒有意義的。然而,在沒有顯式構造方法的情況下,編譯器提供了一個公共的、無參的默認構造方法。對於用戶來說,該構造方法與其他構造方法沒有什么區別。在已發布的 API中經常看到無意識的被實例的類。
試圖通過創建抽象類來強制執行非實例化是行不通的。該類可以被子類化,子類可以被實例化。此外,它誤導用戶認為該類是為繼承而設計的(條目 19)。不過,有一個簡單的方法來確保非實例化。只有當類不包含顯式構造方法時,才會生成一個默認構造方法,因此可以通過包含一個私有構造方法來實現類的非實例化:
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}
因為顯式構造方法是私有的,所以在類之外是不可訪問的。AssertionError
異常不是嚴格要求的,但是它提供了一種保證,以防在類中意外地調用構造方法。它保證類在任何情況下都不會被實例化。這個習慣用法有點違反直覺,好像構造方法就是設計成不能調用的一樣。因此,如前面所示,添加注釋是種明智的做法。
這種習慣有一個副作用,阻止了類的子類化。所有的構造方法都必須顯式或隱式地調用父類構造方法,而子類則沒有可訪問的父類構造方法來調用。