1. 程式人生 > >使用私有構造方法或者列舉型別實現單例

使用私有構造方法或者列舉型別實現單例

單例(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

 getInstance() {

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();

}

}

}

}

}