4

I'm quite confused. I found many implementations of the Singleton Design Pattern in java. One of the implementations I found is the following:

public class MySingleton {

    private static class Loader {
        static MySingleton INSTANCE = new MySingleton();
    }

    private MySingleton () {}

    public static MySingleton getInstance() {
        return Loader.INSTANCE;
    }
}

as explained here: https://stackoverflow.com. Now, if this implementation should work, why doesn't the following?

public class MySingleton {

    private static final MySingleton INSTANCE = new MySingleton();

    private MySingleton () {}

    public static MySingleton getInstance() {
        return INSTANCE;
    }
}

I searched around how java handles initializations, but couldn't find anything showing the latter code will not work. Instead, I found the following: stackoverflow.com, which points out that every static initialization happen before a static method of the class is invoked, so the static field holding the singleton instance should be initialized when the only method accessing INSTANCE (getInstance) is invoked. So yes, i'm really confused: if this code works, why not using this simpler version of the singleton design pattern?

taran95
  • 69
  • 5

2 Answers2

5

The both work and are valid implementation of the singleton.
The first one uses a lazy initialization.
It means that the singleton is created only as getInstance() is invoked by a client.
The second one uses an eager initialization.
It means that the singleton is created as soon as the MySingleton class is loaded by the classloader.

In practice, it doesn't make a big difference because generally getInstance() and the singleton class loading are often coupled.
It is indeed rare to have a client class that refers to a singleton class without requesting its instance via getInstance().

So, in the general case, the second way (eager initialization) that is more concise should be favored.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • What about concerns about being able to create additional instances of the class via reflection? – nasukkin Aug 25 '17 at 20:59
  • @nasukkin Neither way addresses that concern, so it is irrelevant to this question. – Andreas Aug 25 '17 at 21:00
  • @nasukkin Many things may be changed by reflection. Fields without mutators, fields with `final` modifiers, etc... If you provide a component to clients and that you need/want to protect class definitions and object states, using an enum for singleton is fine but it would be certainly not enough. As public components is clearly not the matter, referencing this concern would bring more confusion than other thing. – davidxxx Aug 25 '17 at 21:24
1

Java's built-in implementation of the singleton pattern is enum. When you define an enum, you declare and initialize (aka "enumerate") all of the instances that can ever possibly exist in the runtime. The approach provided in your original question has vulnerabilities; a clever user can create new, unmanaged instances of your "singleton" class. (I'd recommend reading Joshua Bloch's "Effective Java" book for his examples on how this can be accomplished.)

You should consider implementing your singleton like so:

public enum MySingleton {
    INSTANCE();

    /* delcare instance fields here. */

    /** constructor; give it params if you need to. */
    public MySingleton() {
        // initialize whatever you need here.
    }

    /* methods you'll use go here. */
}

When you need your singleton, you would simply reference it as MySingleton.INSTANCE.

nasukkin
  • 2,460
  • 1
  • 12
  • 19
  • Syntax error: *Illegal modifier for the enum constructor; only private is permitted.* – Andreas Aug 25 '17 at 21:02
  • @Andreas you get Syntax error because you define an enum writing INSTANCE; (without the brackets) – taran95 Aug 25 '17 at 21:35
  • @taran95 No, I get syntax error because the constructor is `public`, and only `private` is allowed, *exactly like the error says*. – Andreas Aug 25 '17 at 21:43
  • To be exact, `package-private` (default access modifier) and `private` are allowed. – davidxxx Aug 25 '17 at 21:57