Effective Java Item3:使用私有構造方法或者枚舉類型實現單例

Item3 Enforce the singleton property with a private constructor or an enum type

使用私有構造方法或者枚舉類型實現單例。

 

單例(Singleton)是指只實例化一次的類。

單例表示本質上唯一的系統組件,例如文件系統或者窗口管理器。

package com.googlecode.javatips4u.effectivejava.singleton;

 

public class StaticFinalFieldSingleton {

      public static final StaticFinalFieldSingleton INSTANCE = new StaticFinalFieldSingleton();

 

      private StaticFinalFieldSingleton() {

      }

}

當類StaticFinalFieldSingleton類被實例化時,有且僅有一個StaticFinalFieldSingleton實例存在。

(除非客戶端通過類反射機制調用該私有的構造方法,否則外部無法改變單例)

package com.googlecode.javatips4u.effectivejava.singleton;

 

public class StaticFactoryMethodSingleton {

 

      private static final StaticFactoryMethodSingleton INSTANCE = new StaticFactoryMethodSingleton();

 

      private StaticFactoryMethodSingleton() {

      }

 

      public static StaticFactoryMethodSingleton getInstance() {

            return INSTANCE;

      }

}

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()方法,那麼writereadobject是不同的實例。

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;

 

public class SerializableSingleton implements Serializable {

 

      private String mDesc = "I am transient";

 

      private static final long serialVersionUID = 1L;

      private static final SerializableSingleton INSTANCE = new SerializableSingleton();

 

      private SerializableSingleton() {

      }

 

      public static SerializableSingleton getInstance() {

            return INSTANCE;

      }

 

      public String getDesc() {

            return mDesc;

      }

 

      public void setDesc(String desc) {

            this.mDesc = desc;

      }

 

      // readResolve method to preserve singleton property

      public Object readResolve() {

            return INSTANCE;

      }

 

      public static void 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;

 

public enum EnumSingleton implements Serializable {

 

      INSTANCE;

      private String book = null;

 

      public String getBook() {

            return book;

      }

 

      public void setBook(String book) {

            this.book = book;

      }

 

      public void doSomething() {

      };

}

 

class EnumSingletonSerialization {

      public static void 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();

                        }

                  }

            }

      }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章