使用私有构造方法或者枚举类型实现单例

9 篇文章 0 订阅
1 篇文章 0 订阅

单例(Singleton)是指只实例化一次的类。

单例表示本质上唯一的系统组件,例如文件系统或者窗口管理器。

package com.googlecode.javatips4u.effectivejava.singleton;

 

public class StaticFinalFieldSingleton {

      public static final StaticFinalFieldSingleton INSTANCE = newStaticFinalFieldSingleton();

 

      private StaticFinalFieldSingleton() {

      }

}

当类StaticFinalFieldSingleton类被实例化时,有且仅有一个StaticFinalFieldSingleton实例存在。

(除非客户端通过类反射机制调用该私有的构造方法,否则外部无法改变单例)

package com.googlecode.javatips4u.effectivejava.singleton;

 

public class StaticFactoryMethodSingleton {

 

      private static final StaticFactoryMethodSingleton INSTANCE = newStaticFactoryMethodSingleton();

 

      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()方法,那么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;

 

public class SerializableSingleton implements Serializable {

 

      private String mDesc = "I am transient";

 

      private static final long serialVersionUID = 1L;

      private static final SerializableSingleton INSTANCE = newSerializableSingleton();

 

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

                        }

                  }

            }

      }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值