在Java中實現單例模式的有效方法是什么?在Java中實現單例模式的有效方法是什么?
5 回答
ITMISS
TA貢獻1871條經驗 獲得超8個贊
根據用途,有幾個“正確”的答案。
從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關鍵字讓用戶知道它是最終的。然后,您需要將構造函數設置為私有,以防止用戶創建自己的Foo。從構造函數中拋出異常會阻止用戶使用反射來創建第二個Foo。然后創建一個private static final Foo字段來保存唯一的實例,并創建一個public static Foo getInstance()返回它的方法。Java規范確保僅在首次使用類時調用構造函數。
當你有一個非常大的對象或繁重的構造代碼并且還有其他可訪問的靜態方法或字段可能在需要實例之前使用時,那么你只需要使用延遲初始化。
您可以使用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時執行,因此它負責延遲實例化,并且保證是線程安全的。
當您還希望能夠序列化對象時,需要確保反序列化不會創建副本。
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()將確保將返回唯一的實例,即使該對象在上一次運行的程序中被序列化也是如此。
添加回答
舉報
0/150
提交
取消
