You recently delved into the singleton design pattern, how to implement it in Java, and what it is for. But what if I tell you that Java comes with its own singleton out of the box? Intrigued? Then let's dive in.

You probably already know about the Enum class. It has a special feature that you should be aware of. Specifically, Enum implements the singleton design pattern. This option is almost the same as the singleton approach involving a public field.

Singleton as enum:


public enum Device {   
    PRINTER	
} 
    

Singleton as a public variable:


public class Printer {   
    public static final Printer PRINTER = new Printer();   
    private Printer() {
    }
//…
}
    

The enum approach is more compact than the public-field approach, since we don't need to write our own implementation. Most importantly, enums have no problems with serialization.

Serialization of enums works differently than it does for ordinary objects: only the value of the enum name is serialized. During deserialization, the method is used with the deserialized name to get an instance. Additionally, enum can protect you against reflection attacks.

You'll learn more about reflection in the lessons in the second module, where we will explore the Reflection API.

Java prohibits instantiating enums —a limitation baked into the implementation of the Constructor class's newInstance method, which is often called when creating objects through reflection.

Excerpt of code from Constructor.newInstance. Used to create an enum:


if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
    

The disadvantages of using an enum to create a singleton include:

  • Lack of lazy initialization, since the object is created immediately and initialization cannot be delayed.

  • Other classes cannot be extended. That is, in cases where you need to inherit another class, it won't work to use an enum as a singleton. In such cases, we need to turn to the other implementation options already familiar to us: a static method or a public variable.

  • When using enum as a singleton, you can only use one enum field.


public enum Device extends Electricity { 
    PRINTER 
}
    

This code will give us a compilation error:

No extends clause allowed for enum

But if we need to implement an interface, there is no problem, since enum can implement interfaces:


public enum Device implements Electricity { 
    PRINTER 
}
    

If you don't need to use inheritance, it's best to implement the singleton pattern via enum. We aren't alone in recommending this — Joshua Bloch himself does as well.

This implementation approach gives you convenience, compactness, serialization out of the box, protection from reflection attacks, and uniqueness — everything that a good singleton needs!