EffectiveJava-Singleton Using Enum

Two ways of Implement Singleton using Private Constructor and their drwabacks

Method A: Simply make a static field to hold the instance, initiating it when the class is loaded

1
2
3
4
5
public class StaticFieldSingleton {
public static final StaticFieldSingleton SINGLETON_INSTANCE = new StaticFieldSingleton();

private StaticFieldSingleton() {}
}

Method B: Static Factory Method

1
2
3
4
5
6
7
8
9
10
11
public static StaticFactorySingleton SINGLETON;

private StaticFactorySingleton() {}

// If not using Lazy mode, just simple initiate the field when the class is loaded, and make it as final.
// one draw back of using lazy mode is that the static field cannot be final, which makes a drawback that
// attackers can use reflection to change the SINGLETON field to null, in that case, you would not be able to
// prevent creating multiple instances by checking if the SINGELTON is null before creating it.
public static StaticFactorySingleton getInstanceLazyMode() {
return SINGLETON == null? new StaticFactorySingleton(): SINGLETON;
}

DrawBack

When doing serialization the singleton breaks.

Since when the class wants to do the serialization, it would have to inherent Serialization interface, then, the deserialization process would create a new object, no matter the constructor is private or public, since the constructor is called by the class itself.

To sovle it, can add a readSolve() method, so that the code would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class StaticFactorySingleton implements Serializable {
public static StaticFactorySingleton SINGLETON;

private StaticFactorySingleton() {}

// If not using Lazy mode, just simple initiate the field when the class is loaded, and make it as final.
// one draw back of using lazy mode is that the static field cannot be final, which makes a drawback that
// attackers can use reflection to change the SINGLETON field to null, in that case, you would not be able to
// prevent creating multiple instances by checking if the SINGELTON is null before creating it.
public static StaticFactorySingleton getInstanceLazyMode() {
return SINGLETON == null? new StaticFactorySingleton(): SINGLETON;
}

@Serial
protected Object readResolve() {
return SINGLETON;
}
}

Using using reflection the singleton breaks.

When doing the reflection, you can create the instance no matter the constructor is private or public. So to prevent this, within the scope of not using Enum, you can probably:

  1. Check if the instance is created every time when the constructor is called, like this:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class StaticFactorySingleton implements Serializable {
    public static StaticFactorySingleton SINGLETON;

    private StaticFactorySingleton() {
    if (SINGLETON != null)
    throw new IllegalCallerException("Instance already initiated");
    }

    // If not using Lazy mode, just simple initiate the field when the class is loaded, and make it as final.
    // one draw back of using lazy mode is that the static field cannot be final, which makes a drawback that
    // attackers can use reflection to change the SINGLETON field to null, in that case, you would not be able to
    // prevent creating multiple instances by checking if the SINGELTON is null before creating it.
    public static StaticFactorySingleton getInstanceLazyMode() {
    return SINGLETON == null? new StaticFactorySingleton(): SINGLETON;
    }

    @Serial
    protected Object readResolve() {
    return SINGLETON;
    }
    }
  2. However, above code still has problem, what if the hacker use reflection to modify the SINGLETON from non-null to null value?

    In this case, we can specify SINGLETON as final, so that the reflection won’t be able to change it value. However, this gives another drawback that you won’t be able to use static factory method to achieve the singleton.

Using Enum to implement Singleton

Enum in Java is natually inherent Serializable, which means it won’t need to explicitly implement the Serialiable Interface, and there is no problem of breaking the singleton when doing serialization.

Secondly, Enum’s instance would only be initiated only once and users can not touch it since **JVM handles the creation and invocation of enum constructors internally**.

Thus, all the above problems sovled.

How to use

Just create a Enum like a normal class, then get the instance like below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum SingletonEnum {
INSTANCE;

int val;

SingletonEnum() {
val = 0;
}

public void printVal() {
System.out.println(val);
}

// add any public/private methods you want.

}
1
2
3
4
5
6
7
8
public class TestEnumSingleton {
public static void main(String[] args) {
SingletonEnum singleton = SingletonEnum.INSTANCE;
singleton.printVal();
singleton.val = 9;
singleton.printVal();
}
}