Singleton with public final field
Problem of this is that this can create another instance by reflection. The fix is that in private method, add a INSTANCE check.
public class SingletonWithPublicFinalField {
public static final SingletonWithPublicFinalField INSTANCE = new SingletonWithPublicFinalField();
private SingletonWithPublicFinalField() {
// if (INSTANCE != null) {
// throw new RuntimeException("Singleton instance already existed");
// }
}
public static void main(String[] args) throws Exception{
SingletonWithPublicFinalField instance1 = SingletonWithPublicFinalField.INSTANCE;
System.out.println(instance1);
Constructor.setAccessible(SingletonWithPublicFinalField.class.getConstructors(), true);
Object instance2 = Class.forName(SingletonWithPublicFinalField.class.getName()).newInstance();
System.out.println(instance2);
}
}
Singleton with public static factory method. Good of it is that it is very like a class. It is easy to convert it into a normal non-singleton class. Just rewrite getInstance() method.
public class SingletonWithPublicStaticFactoryMethod {
public static final SingletonWithPublicStaticFactoryMethod INSTANCE = new SingletonWithPublicStaticFactoryMethod();
private SingletonWithPublicStaticFactoryMethod() {}
public static SingletonWithPublicStaticFactoryMethod getInstance() {
return INSTANCE;
}
public static void main(String[] args) throws Exception{
SingletonWithPublicStaticFactoryMethod instance = SingletonWithPublicStaticFactoryMethod.getInstance();
System.out.println(instance);
}
}
Singleton serializable issue. When deserializing, it creates a different instance. The fix is to override readResolve() method and return the INSTANCE.
public class SingletonWithSerializable implements Serializable {
public static final SingletonWithSerializable INSTANCE = new SingletonWithSerializable();
private SingletonWithSerializable() {}
public static SingletonWithSerializable getInstance() {
return INSTANCE;
}
// When deserializing, it returns a different instance. The fix is to add below
// private Object readRsolve() {
// return INSTANCE;
// }
public static void main(String[] args) throws Exception{
SingletonWithSerializable instance = SingletonWithSerializable.getInstance();
System.out.println(instance);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file1.ser"))) {
out.writeObject(instance);
}
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("file1.ser"))) {
SingletonWithSerializable readObject = (SingletonWithSerializable) in.readObject();
System.out.println(readObject);
}
}
}
The best option is to use enum singleton. It avoids reflection hacking or serializing issue very easily.
public enum SingletonWithEnum {
INSTANCE;
public void doSomeMethod() {
System.out.println("some method");
}
public static void main(String[] args) throws Exception {
SingletonWithEnum singletonWithEnum = SingletonWithEnum.INSTANCE;
SingletonWithEnum instance = SingletonWithEnum.INSTANCE;
System.out.println(instance);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file1.ser"))) {
out.writeObject(instance);
}
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("file1.ser"))) {
SingletonWithEnum readObject = (SingletonWithEnum) in.readObject();
System.out.println(readObject);
}
instance.doSomeMethod();
}
}