5 回答

TA貢獻1871條經(jīng)驗 獲得超8個贊
根據(jù)用途,有幾個“正確”的答案。
從java5開始,最好的方法是使用枚舉:
public enum Foo { INSTANCE;}
前java5,最簡單的情況是:
public final class Foo { private static final Foo INSTANCE = new Foo(); private Foo() { if (INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { return INSTANCE; } public Object clone() throws CloneNotSupportedException{ throw new CloneNotSupportedException("Cannot clone instance of this class"); }}
我們來看看代碼吧。首先,你希望課程是最終的。在這種情況下,我使用了final
關(guān)鍵字讓用戶知道它是最終的。然后,您需要將構(gòu)造函數(shù)設置為私有,以防止用戶創(chuàng)建自己的Foo。從構(gòu)造函數(shù)中拋出異常會阻止用戶使用反射來創(chuàng)建第二個Foo。然后創(chuàng)建一個private static final Foo
字段來保存唯一的實例,并創(chuàng)建一個public static Foo getInstance()
返回它的方法。Java規(guī)范確保僅在首次使用類時調(diào)用構(gòu)造函數(shù)。
當你有一個非常大的對象或繁重的構(gòu)造代碼并且還有其他可訪問的靜態(tài)方法或字段可能在需要實例之前使用時,那么你只需要使用延遲初始化。
您可以使用a private static class
來加載實例。然后代碼看起來像:
public final class Foo { private static class FooLoader { private static final Foo INSTANCE = new Foo(); } private Foo() { if (FooLoader.INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { return FooLoader.INSTANCE; }}
由于該行private static final Foo INSTANCE = new Foo();
僅在實際使用類FooLoader時執(zhí)行,因此它負責延遲實例化,并且保證是線程安全的。
當您還希望能夠序列化對象時,需要確保反序列化不會創(chuàng)建副本。
public final class Foo implements Serializable { private static final long serialVersionUID = 1L; private static class FooLoader { private static final Foo INSTANCE = new Foo(); } private Foo() { if (FooLoader.INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } } public static Foo getInstance() { return FooLoader.INSTANCE; } @SuppressWarnings("unused") private Foo readResolve() { return FooLoader.INSTANCE; }}
該方法readResolve()
將確保將返回唯一的實例,即使該對象在上一次運行的程序中被序列化也是如此。
添加回答
舉報