第4項:經過私有構造器強化不可實例化的能力

  有時候你會想要編寫一個只包含一組靜態方法和靜態字段的類。這種類名聲很很差,由於有些人爲了不使用面向對象的思惟方式而濫用這樣的類(some people abuse them to avoid thinking in terms of objects),可是他們確實有它們特有的用處。咱們可使用這種類,以java.lang.Math或者 java.util.Arrays的方式對原始值或數組的相關方法組織起來。它們還能夠用於以java.util.Collections的方式,把實現特定接口的對象上的靜態方法(包括工廠:第1項)組織起來。(從Java 8開始,你也能夠將這些方法放在接口中,假設它是你本身修改的)。最後,這些類能夠用於對final類的方法組織起來,經過這種方式用以取代擴展該類的作法。java

  這種工具類不但願被實例化,實例化對它沒有任何意義。然而,在沒有顯式構造函數的狀況下,編譯器會默認提供一個公共的、無參的默認構造函數。對於用戶而言,這個構造器與其餘構造器沒有任何區別。在已發行的API中經常能夠看到一些被無心識地實例化的類。數組

  企圖經過將該類作成抽象類來強制該類不可被實例化,這是行不通的。該類能夠被子類化,而且該子類也能夠被實例化。這樣作甚至會誤導用戶,覺得這種類是專門爲了繼承而設計的(第19項)。然而,有一些簡單的習慣用法能夠確保類不可被實例化。因爲只有當類不包含顯示的構造器時,編譯器纔會生成缺省的構造器,所以咱們只要讓這個類包含私有構造器,他就不能被實例化了:函數

// Noninstantiable utility class
public class UtilityClass {
    // Suppress default constructor for noninstantiability
    private UtilityClass(( {
        throw new AssertionError();
    }
    ... // Remainder omitted
}

  由於顯示構造函數是私有的,因此它在類外是不可訪問的,AssertionError不是必需的,可是它能夠避免不當心在類的內部調用構造器。它保證該類在任何狀況下都不會實例化。這種習慣用法有點違背直覺,好像構造器就是專門設計成不能被調用同樣。所以明智的作法就是在代碼中增長一條註釋,如上所示。工具

  這種習慣用法也有反作用,它使得一個類不能擁有子類。由於子類的全部構造函數都必須顯示或者隱式地調用父類的構造函數,在這種情形下,子類就沒有可訪問的父類構造器可用了。spa

我的公衆號同步更新

相關文章
相關標籤/搜索