使用私有構造方法或者列舉型別實現單例
單例(Singleton)是指只例項化一次的類。
單例表示本質上唯一的系統元件,例如檔案系統或者視窗管理器。
package com.googlecode.javatips4u.effectivejava.singleton;
publicclass StaticFinalFieldSingleton {
publicstaticfinal StaticFinalFieldSingleton INSTANCE = newStaticFinalFieldSingleton();
private StaticFinalFieldSingleton() {
}
}
當類StaticFinalFieldSingleton類被例項化時,有且僅有一個StaticFinalFieldSingleton例項存在。
(除非客戶端通過類反射機制呼叫該私有的構造方法,否則外部無法改變單例)
package com.googlecode.javatips4u.effectivejava.singleton;
publicclass StaticFactoryMethodSingleton {
privatestaticfinal StaticFactoryMethodSingleton INSTANCE = newStaticFactoryMethodSingleton();
private StaticFactoryMethodSingleton() {
}
publicstatic StaticFactoryMethodSingleton
returnINSTANCE;
}
}
public static final成員的優點在於客戶端很容易分辨是單例。static(整個類公用的)final(不能改變的)確保例項是相同物件的引用。
public static method的優點在於增加了靈活性,可以修改方法內部而不引起客戶端API的改變,例如每個執行緒一個單例。另外一個有點在於涉及到泛型的時候(Item27)。
Item27:
當對單例類進行Serializable處理時,僅僅實現Serializable介面還是不夠的,確切的說,如果只是實現Serializable介面,那麼被readObject讀取的例項並不是writeObject時儲存的類。
需要將所有的例項成員設定為transient(why???),然後實現readResolve()方法:
ObjectInputStream.readObject() -> ObjectInputStream.readObject0(boolean) -> ... -> Method.invoke() -> ... SerializableSingleton.readResolve()
例如在下面的例子中,如果不實現readResolve()方法,那麼write和read的object是不同的例項。
package com.googlecode.javatips4u.effectivejava.singleton;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
publicclass SerializableSingleton implements Serializable {
private String mDesc = "I am transient";
privatestaticfinallongserialVersionUID = 1L;
privatestaticfinal SerializableSingleton INSTANCE = newSerializableSingleton();
private SerializableSingleton() {
}
publicstatic SerializableSingleton getInstance() {
returnINSTANCE;
}
public String getDesc() {
returnmDesc;
}
publicvoid setDesc(String desc) {
this.mDesc = desc;
}
// readResolve method to preserve singleton property
public Object readResolve() {
returnINSTANCE;
}
publicstaticvoid main(String[] args) {
File file = new File("singleton");
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
SerializableSingleton instance = SerializableSingleton
.getInstance();
instance.setDesc("I changed you!");
System.out.println(instance);
oos.writeObject(instance);
oos.close();
ois = new ObjectInputStream(new FileInputStream(file));
SerializableSingleton instance2 = (SerializableSingleton) ois
.readObject();
System.out.println(instance2);
System.out.println(instance2.getDesc());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
在Java1.5中,還有另外一種方法來實現單例,那就是列舉型別:a single-element enum type is the best way to implement a singleton.單元素的列舉型別是實現單例的最好方式。
package com.googlecode.javatips4u.effectivejava.singleton;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
publicenum EnumSingleton implements Serializable {
INSTANCE;
private String book = null;
public String getBook() {
returnbook;
}
publicvoid setBook(String book) {
this.book = book;
}
publicvoid doSomething() {
};
}
class EnumSingletonSerialization {
publicstaticvoid main(String[] args) {
File file = new File("singleton");
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
EnumSingleton singleton = EnumSingleton.INSTANCE;
singleton.setBook("HelloWorld");
oos.writeObject(EnumSingleton.INSTANCE);
System.out.println(EnumSingleton.INSTANCE);
oos.close();
ois = new ObjectInputStream(new FileInputStream(file));
EnumSingleton singleton2 = (EnumSingleton) ois.readObject();
System.out.println(singleton2.getBook());
System.out.println(singleton == singleton2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}