DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • JSON Handling With GSON in Java With OOP Essence
  • High-Performance Java Serialization to Different Formats
  • Did You Know the Fastest Way of Serializing a Java Field Is Not Serializing It at All?
  • How to Introduce a New API Quickly Using Micronaut

Trending

  • Implementing API Design First in .NET for Efficient Development, Testing, and CI/CD
  • AI Speaks for the World... But Whose Humanity Does It Learn From?
  • Orchestrating Microservices with Dapr: A Unified Approach
  • How to Ensure Cross-Time Zone Data Integrity and Consistency in Global Data Pipelines
  1. DZone
  2. Coding
  3. Java
  4. Java Singletons Using Enum

Java Singletons Using Enum

When making singleton classes, consider using an enum. It solves the problems that can crop up with (de)serialization and reflection.

By 
Dulaj Atapattu user avatar
Dulaj Atapattu
·
Jul. 21, 17 · Tutorial
Likes (39)
Comment
Save
Tweet
Share
259.8K Views

Join the DZone community and get the full member experience.

Join For Free

Image title

A singleton is a class that is supposed to have only one instance per JVM. The Same instance of the singleton class is reused by multiple threads. Most often, we use singletons to represent system configurations and window managers, since those instances should be common to all threads and objects within a JVM.

Traditional Methods of Making Singletons

There are several popular methods for making singletons.

Method 1: Singleton With Public Static Final Field

public class Singleton {

    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

}


Method 2: Singleton With Public Static Factory Method

public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance(){
        return INSTANCE;
    }

}


Method 3: Singleton With Lazy Initialization

public class Singleton {

    private static Singleton INSTANCE = null;

    private Singleton() {}

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }

}


The Premium Java Programming Certification Bundle.*

*Affiliate link. See Terms of Use.

Pros and Cons of the Above Methods

All of the above methods enforce non-insatiability (unable to make instances) using a private constructor. Here we cannot avoid creating a private constructor even though we have nothing to do inside of it. Because if we do so, then an implicit parameterless default constructor is created with the same access modifier as the class. For example, if the class is declared public, then the default constructor is public; if the class is declared protected, then the default constructor is protected (Refer to the Oracle docs for more details).

Comparing the above methods, the first two methods don't have a performance difference at all. Method 1 is clearer and simpler. A minor advantage of Method 2 is that later, you can make the class a non-singleton without changing the API. You can do it by changing the implementation of the factory method to create a new instance for every call instead of returning the same instance as follows.

public static Singleton getInstance() {
    return new Singleton ();
}


Static fields are initialized at class loading time. Therefore, in both Methods 1 and 2, singleton instances are created even in a case we don't use them at runtime. This is not a problem as long as the singleton object is not too big and creating the instance is not too expensive. Method 3 avoids this problem with lazy initialization. In Method 3, the instance is created when we access the singleton object for the first time. Fine-grained synchronization is used to ensure that no more than one object is created with multiple concurrent threads. 

All of the above methods work fine until you are not doing serialization and deserialization with a singleton class. Let's think again: How did we achieve the singleton behavior in above methods? It was done by making the constructor private and making the constructor inaccessible for creating new instances of the class. But isn't there any other ways to create an instance of a class other than the constructor? The answer is no. There are some other advanced methods.

  1. Serialization and deserialization
  2. Reflection

Problems With Serialization and Deserialization

In order to serialize the above singleton classes, we must implement those classes with a Serializable interface. But doing that is not enough. When deserializing a class, new instances are created. Now it doesn't matter the constructor is private or not. Now there can be more than one instance of the same singleton class inside the JVM, violating the singleton property. 

public class SerializeDemo implements Serializable {

    public static void main(String[] args) {
        Singleton singleton = Singleton.INSTANCE;
        singleton.setValue(1);

        // Serialize
        try {
            FileOutputStream fileOut = new FileOutputStream("out.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(singleton);
            out.close();
            fileOut.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        singleton.setValue(2);

        // Deserialize
        Singleton singleton2 = null;
        try {
            FileInputStream fileIn = new FileInputStream("out.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            singleton2 = (Singleton) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException i) {
            i.printStackTrace();
        } catch (ClassNotFoundException c) {
            System.out.println("singletons.SingletonEnum class not found");
            c.printStackTrace();
        }

        if (singleton == singleton2) {
            System.out.println("Two objects are same");
        } else {
            System.out.println("Two objects are not same");
        }

        System.out.println(singleton.getValue());
        System.out.println(singleton2.getValue());

    }

}


The output for the above code is:

Two objects are not same
2
1


Here, singleton and singleton2 are two different instances having two different values as their field variables. This violates the singleton property. The solution is that we have to implement the readResolve method, which is called when preparing the deserialized object before returning it to the caller. The solution is as follows.

public class Singleton implements Serializable{

    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }

    protected Object readResolve() {
        return INSTANCE;
    }

}


Now the output for above code will be:

Two objects are same
2
2


Now the singleton property is preserved, and only one instance of the singleton class exists within the JVM.

Problems With Reflection

An advanced user can change the private access modifier of the constructor to anything they want at runtime using reflection. If this happens, our only mechanism for non-instantiability breaks. Let's see how this can be done.

public class ReflectionDemo {

    public static void main(String[] args) throws Exception {
        Singleton singleton = Singleton.INSTANCE;

        Constructor constructor = singleton.getClass().getDeclaredConstructor(new Class[0]);
        constructor.setAccessible(true);

        Singleton singleton2 = (Singleton) constructor.newInstance();

        if (singleton == singleton2) {
            System.out.println("Two objects are same");
        } else {
            System.out.println("Two objects are not same");
        }

        singleton.setValue(1);
        singleton2.setValue(2);

        System.out.println(singleton.getValue());
        System.out.println(singleton2.getValue());

    }
}


Output:

Two objects are not same
1
2


In this way, the non-accessible private constructor becomes accessible and the whole idea of making the class a singleton breaks.

Making Singletons With Enum in Java

All of the above problems can be solved very easily by using the enum type to make singletons.

Singleton With Enum

public enum Singleton {
    INSTANCE;
}


The three lines above make a singleton without any of the problems discussed. Since enums are inherently serializable, we don't need to implement it with a serializable interface. The reflection problem is also not there. Therefore, it is 100% guaranteed that only one instance of the singleton is present within a JVM. Thus, this method is recommended as the best method of making singletons in Java.

How to Use

public enum SingletonEnum {
    INSTANCE;

    int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}


Main class implementation:

public class EnumDemo {

    public static void main(String[] args) {
        SingletonEnum singleton = SingletonEnum.INSTANCE;

        System.out.println(singleton.getValue());
        singleton.setValue(2);
        System.out.println(singleton.getValue());
    }
}


One thing to remember here is, when serializing an enum, field variables are not getting serialized. For example, if we serialize and deserialize the SingletonEnum class, we will lose the value of the int value field (Refer to the Oracle docs for more details about enum serialization).

All the source code related to this post can be found here.

Java (programming language) Serialization Object type (object-oriented programming)

Published at DZone with permission of Dulaj Atapattu. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • JSON Handling With GSON in Java With OOP Essence
  • High-Performance Java Serialization to Different Formats
  • Did You Know the Fastest Way of Serializing a Java Field Is Not Serializing It at All?
  • How to Introduce a New API Quickly Using Micronaut

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!