logo

Singleton

Last Updated: 2021-12-12

入门。

Singleton 被翻译作“单例”,也就是说这个类(class)只有这一个实例(instance)。在 Java 中可以这样实现:

class Singleton {
  private static Singleton instance = new Singleton();

  private Singleton() {}

  public static Singleton getInstance() {
    return instance;
  }
}

首先这个类不提供public的构造函数,这样保证不能通过构造函数创建新的实例;其次它有一个private static的实例,不可以被外面直接访问或重新赋值;最后只提供一个get方法来获得这个实例,而没有set

放弃?

这个方法是否有效呢?

// 注:需要import java.lang.reflect.Constructor;

// 获得Singleton的实例
Singleton instance1 = Singleton.getInstance();

// 通过reflection获得构造函数
Constructor constructor = Singleton.class.getDeclaredConstructors()[0];

// 将构造函数设置为可以访问
constructor.setAccessible(true);

// 创建另一个实例
Singleton instance2 = (Singleton) constructor.newInstance();

// 比较两个实例
System.out.println(instance1.equals(instance2)); // => false
System.out.println(instance1.hashCode()); // => 1239731077
System.out.println(instance2.hashCode()); // => 357863579

可以看到这是两个完全不同的实例,有着不一样的hashCode

另一个例子:给 Singleton 加上 Serializable 的接口

class Singleton implements Serializable {
  ...
}
// serialize the instance to file
Singleton instance1 = Singleton.getInstance();
try (ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.data"))) {
  out.writeObject(instance1);
}

// deserailize from file to object
try (ObjectInput in = new ObjectInputStream(new FileInputStream("file.data"))) {
  Singleton instance2 = (Singleton) in.readObject();
  System.out.println(instance1.hashCode()); // => 152005629
  System.out.println(instance2.hashCode()); // => 1307096070
}

可以看到两个实例又是不同的。

进阶!

(更新中。。。)

https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom

http://haokanga.github.io/java/2017/08/09/java-singleton-pattern.html

https://www.geeksforgeeks.org/prevent-singleton-pattern-reflection-serialization-cloning/