Singleton design pattern – restricting all 4 ways of Object creation in Java

In this article, we will discuss Singleton design pattern with example. Before delving more into topic, we will understand what is Singleton design pattern?

 

What is Singleton design pattern?

Singleton design pattern is the

  • solution proposed to return same instance every time
  • restrict instantiation of a class more than once
  • exactly one copy is available at any given point of time
  • ensures only one instance is available in a Java Virtual Machine (JVM)

So, to create singleton design pattern or singleton class in Java, we need to restrict all possible ways to create object from outside the class

 

Now, we will revisit & understand what all possible ways to create object in Java

 

Different ways to create object in Java:

Primarily, there are only 4 ways to create object in Java, those are;

  • Using new operator or keyword
  • Using clone method of Object class
  • Using Object De-serialization
  • Using Reflection API & newInstance() method

Further using reflection API & newInstance() method, we can derive multiple ways to create objects in Java;

Using Reflection API & newInstance() method:

  1. Using Class.forName(“fully.qualified.name.of.class”).newInstance();
  2. Using <ClassName>.class.newInstance();
  3. Using <ClassName>.class.getClassLoader().loadClass(“fully.qualified.name.of.class”).newInstance();
  4. Using Constructor i.e.;
    Constructor<<className>> constructor = <ClassName>.class.getConstructor();
    <ClassName> object44 = constructor.newInstance();

Read here for complete details on various ways to create object in Java

 

Singleton class:

To create singleton class in Java, we need to suppress all possible ways to create object from outside class

In short, we need to restrict all 4 (FOUR) possible ways to create object in Java

Way Object creation ways How to restrict 
1 new operator or keyword Provide private constructor, so that no-one outside of class can instantiate object;
2 clone() method of Object class Override clone() method by implementing Cloneable interface and throw CloneNotSupportedException();
3 Object de-serialization Override readResolve() method by implementing Serializable interface and return same INSTANCE every time;
4 Reflection API & newInstance() As we are already providing private constructor to restrict object creation using new operator from outside class;

This will help to restrict object creation using reflection API & newInstance() method;

because newInstance() method requires default public no-arg constructor for object creation from outside of class;

 

Steps to create singleton class in Java:

  1. Create INSTANCE of same class by instantiating class & this INSTANCE should be with private & static modifier
  2. Provide public static method that returns same INSTANCE of class every time
  3. Finally, create private constructor so that no-one create object from outside of class
  4. Providing private constructor helps to suppress creating objects either by new operator/keyword or refection API & newInstance() method
  5. If class implements Serializable interface, then override readResolve() method and return same INSTANCE
  6. If class implements Cloneable interface, then override clone() method and throw CloneNotSupportedException();

 

Eager or Lazy Instantiation:

Here, step 1 tells about creating object by instantiating class, it can be done 2 ways;

  1. Eager instantiation by directly creating object using new operator
  2. Lazy instantiatione.; creating object only after checking whether already singleton object is available or NOT

We will discuss 2 demo examples covering both approaches;

 

Assumption:

  • Class implements both Serializable & Cloneable interface
  • We are designing class in such a way that, when cloning is performed then respective overridden clone() method throws Clone not supported exception
  • Executing in a single-threaded environment

 

1. Eager Instantiation:

Here in Student class,

  • Directly one INSTANCE of the class is created/instantiated with private & static modifier
  • Next step is to provide public static method to access Singleton INSTANCE from outside class
  • Finally, providing private constructor for restricting object creation from outside of class
  • By implementing Serializable interface, we are returning same INSTANCE from readResolve() method (as this is the one invoked during object de-serialization process)
  • By implementing Cloneable interface, we are explicitly throwing clone not supported exception from overridden clone() method

Student.java

package in.bench.resources.singleton.design.pattern;

import java.io.ObjectStreamException;
import java.io.Serializable;

public class Student implements Serializable, Cloneable {

	// Eager-Instantiation: only-time INSTANCE created
	private volatile static Student INSTANCE = new Student();

	// private constructor
	private Student() {
		// helps to suppress creating objects either 
		// 1. by new operator/keyword or 
		// 2. by reflection API &amp;amp;amp;amp;amp; newInstance() method
	}

	// create static method to get same instance every time
	public static Student getInstance(){
		return INSTANCE;
	}

	// readResolve method to suppress creating new object during de-serialization
	private Object readResolve() throws ObjectStreamException {
		return INSTANCE;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// directly throw Clone Not Supported Exception
		throw new CloneNotSupportedException();
	}

	// other utility methods and details of this class
}

 

2. Lazy Instantiation:

Here in Employee class,

  • We aren’t instantiating Employee INSTANCE directly (as against Student class in earlier eager-instantiation case)
  • Rather INSTANCE is just declared
  • Later when object is requested invoking getInstance() method
  • Then method checks whether already instantiated singleton INSTANCE is available or NOT
  • This is instantiated only one time i.e.; for the very first time
  • Otherwise, from next request while invoking getInstance() method always returns same instantiated INSTANCE
  • This way performance improves
  • Assumption: above sentences applicable only for single-threaded environment
  • Note: There is serious problem in the below coded Employee class; while working with multi-threaded environment as there is a chance of 2 INSTANCEs getting created
  • Head-over to next section for more detail with examples and explanation while working in a multi-threaded environment

Employee.java

package in.bench.resources.singleton.design.pattern;

import java.io.ObjectStreamException;
import java.io.Serializable;

public class Employee implements Serializable, Cloneable {

	// Lazy-Instantiation: only-time INSTANCE created
	private volatile static Employee INSTANCE;

	// private constructor
	private Employee() {
		// helps to suppress creating objects either 
		// 1. by new operator/keyword or 
		// 2. by reflection API &amp;amp;amp;amp;amp; newInstance() method
	}

	// provide public static getInstance() method returning INSTANCE after checking
	public static Employee getInstance() {

		if(null == INSTANCE){
			INSTANCE = new Employee();
		}
		return INSTANCE;
	}

	// readResolve method to suppress creating new object during de-serialization
	private Object readResolve() throws ObjectStreamException {
		return INSTANCE;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// directly throw Clone Not Supported Exception
		throw new CloneNotSupportedException();
	}

	// other utility methods and details of this class
}

 

Singleton class in a Multi-threaded environment:

For multi-thread environment read the article How to construct a singleton class in a multi-threaded environment in Java

Above article explains,

  • What is Singleton design pattern?
  • Example for Singleton design pattern via eager-instantiation approach
  • Performance improvement by coding lazy-instantiation over eager-instantiation
  • How do handle singleton design pattern in a multi-threaded environment?
  • Brief explanation about Double-Checked Locking pattern?

 

Happy Coding !!
Happy Learning !!

How to construct an immutable class in Java
Various ways to create Object in Java - 4 ways