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 | public class StaticFieldSingleton { |
Method B: Static Factory Method
1 | public static 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 | public class StaticFactorySingleton implements Serializable { |
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:
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
21public 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;
}
protected Object readResolve() {
return SINGLETON;
}
}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 usestatic 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 | public enum SingletonEnum { |
1 | public class TestEnumSingleton { |