I believe everyone starts (and even continues to do so) implementing Singleton pattern in following fashion:
package com.singleton; public class SimpleSingleton { private static SimpleSingleton simpleSingleton; private SimpleSingleton() { }; public static SimpleSingleton getInstance() { if (simpleSingleton == null) simpleSingleton = new SimpleSingleton(); return simpleSingleton; } }
Do you find any problem in it?
Well, I have!!! The contract of Singleton class can be broken.
Let's discuss Singleton pattern in Simple Threaded environment and then in next post I will discuss this pattern in Multithreaded environment.
In a Single Threaded Environment:
Do you remember the double edge sword in Java, "REFLECTION"?
With the help of reflection, one can very easily breach the singleton contract for above class and create as many instance as he wants. Let's consider following three statements:
//Get Private Constructor Constructor pvtConstructor = Class.forName( "com.singleton.SimpleSingleton").getDeclaredConstructors()[0]; //Set its access control pvtConstructor.setAccessible(true); //Invoke Private Constructor SimpleSingleton notSingleton = (SimpleSingleton) pvtConstructor .newInstance(null);
Here is a summary what is happening in above statements:
- First statement retrieves the Constructor object for private constructor of SimpleSingleton class.
- Since the constructor retrieved is a private one, we need to set its accessibility to true.
- Last statement invokes the private constructor and create a new instance of SimpleSingleton class.
Well, prior to Java 1.5, there was no way (at least in my knowledge, but Java Universe is so big that I can't say with 100% surity :) ) to save a singleton class from Reflection mechanism. In Java 1.5, a new kind of classes were introduced, "Enum".
Unlike Classes, an Enum has fix number of objects and since this restriction is implemented by JVM's native libraries, hence it is unbreakable. Let's see an example:
public enum SampleEnum { ONLY_INSTANCE(); }
Now let's try to create an object of SampleEnum using reflection:
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class enumTest { public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException { Constructor c1 = Class.forName("SampleEnum").getDeclaredConstructors()[0]; c1.setAccessible(true); SampleEnum e1 = (SampleEnum) c1.newInstance(null); } }On running this example, it will throw an exception:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:511) at enumTest.main(enumTest.java:11)Clearly, you can't create an object of Enum type.
Hence, we can conclude that best way to implement a Singleton pattern is by using Enum. It is simple, straightforward and unbreakable.
Further, in my next post, I will discuss about Singleton pattern in Multithreaded environment.