ITEM 4: ENFORCE NONINSTANTIABILITY WITH A PRIVATE CONSTRUCTOR
??有時,我們只想寫一個僅擁有靜態(tài)變量和靜態(tài)方法的類,雖然這樣的類名聲不好,因為有些人濫用它們來避免面向?qū)ο蟮乃枷?,但它們確實有用武之地。它們可以用來對一些相關(guān)的方法進行分組,如 java.lang.Math 和java.util.Arrays。也可以用于對靜態(tài)方法進行分組(包括工廠),用于實現(xiàn)某個接口,比如 java.util.Collections (在Java8中,你可以把這些靜態(tài)方法放在接口中)。最后,我們也可以將這種類用于在final類中對方法進行分組,因為不能final類不能被繼承。
??這樣的工具類并不是為實例化而設(shè)計的:實例化毫無意義。然而,在我們沒有提供顯示公共構(gòu)造函數(shù)的情況下,編譯器會自動為我們提供一個。對用戶來說,這個構(gòu)造函數(shù)和其他的類(的公共構(gòu)造函數(shù))沒什么差別。在已發(fā)布的API中經(jīng)常看到無意識地實例化某個類。試圖通過抽象類來強制非實例化是行不通的,這樣的類能夠被繼承,并且子類可以正常實例化。還可能被用戶誤以為該類是為了被繼承而設(shè)計的。然而,有一個辦法可以確保非實例化:只有顯示的聲明構(gòu)造函數(shù)才能阻止編譯器自動生成一個,那么我們可以將構(gòu)造器置為私有來達到目的:
// Noninstantiable utility class
public class UtilityClass {
// Suppress default constructor for noninstantiability
private UtilityClass() {
throw new AssertionError();
}
... // Remainder omitted
}
??由于構(gòu)造期被設(shè)置為private,因此在類外不可訪問。AssertionError 錯誤并不是必須的,但它能夠幫正構(gòu)造函數(shù)不會意外地在類內(nèi)被調(diào)用。這個構(gòu)造函數(shù)保證類在任何情況下都不會被實例化。這個用法有點違反直覺,因為構(gòu)造函數(shù)是明確提供的,但又不能調(diào)用它。因此最好注釋說明。
??還有一個好處,這個用法還可以防止類被繼承。子類所有構(gòu)造函數(shù)都必須顯式或隱式地調(diào)用父類構(gòu)造函數(shù),而子類將無權(quán)訪問父類的構(gòu)造函數(shù)。