Correct implementation of initialization-on-demand holder idiom

12,142

Solution 1

There are several things to explain about singletons and the initialization-on-demand holder idiom. Here we go:

1) The access modifier:

Normally you can't access fields and methods in another class if they are private. They must at least be package private (having no modifier, it is) if the accessing class is in the same package. So the correct way to implement it, would be:

public class Singleton {
    ...
    private static class LazyHolder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return LazyHolder.INSTANCE;
    }
}

However, JLS 6.6.1 explains:

Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

That means, declaring the field INSTANCE as private still allows the access from inside the top level class Singleton. But the compiler must do some tricks to get around the private modifier: It inserts package private methods for getting and setting such a field.

In fact, it does not matter, which modifier you place on it. If it is public, it still cannot be accessed from other classes than Singleton. However ... I think the package private access is the best. Making it public does not makes sense. Making it private forces the compiler to do some tricks. Making it package private reflects what you have: Access to a class member from another class.

2) How to implement a singleton:

If you ever want to consider serialization, the singleton implementation will get a bit difficult. Joshu Bloch wrote a great section in his book "Effective Java" about implementing singletons. At the end, he concluded to simply use an enum for this, as the Java enum specification provides every charecteristic that is needed in regards to singletons. Of course, that does not use the idiom anymore.

3) Considering design:

In most design decisions, singletons do not have their places anymore. In fact, it could indicate a design issue, if you must place a singleton into your program. Keep in mind: Singletons provide a global acess mechanism to some data or services. And this is not OOP.

Solution 2

private static class LazyHolder {
    $VISIBILITY static final Singleton INSTANCE = new Singleton();

From a consumer's point of view it does not really matter if $VISIBILITY is public or private because the LazyHolder type is private. The variable is only accessible via the static method in both cases.

Solution 3

I use number 1 (private INSTANCE) because you generally try to use the narrowest scope as possible. But in this case since the Holder class is private it doesn't really matter. However, suppose someone later decided to make the Holder class public then number 2 could be problematic from an encapsulation perspective (callers could bypass the getInstance() method and access the static field directly).

Share:
12,142

Related videos on Youtube

chain ro
Author by

chain ro

Updated on September 14, 2022

Comments

  • chain ro
    chain ro over 1 year

    I have got two versions of "Initialization-on-demand holder idiom":

    1. http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
    2. http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh

    The major difference between above is that the first one declared INSTANCE as private, but the second one declared INSTANCE as public.

    Please tell me which one should I use.


    Sorry, I have not found the difference between using private and public in my application:

    public class Singleton {
        private int x;
        public int getX() {
            return x;
        }
    
        private Singleton () {}
    
        private static class LazyHolder {
            //both private and public works
            private static final Singleton INSTANCE = new Singleton();
        }
    
        public static Singleton getInstance() {
            return LazyHolder.INSTANCE;
        }
    }
    

    The only thing I do is to call something like Singleton.getInsance().getX(), so both versions works. Thus I want to know the situations for using them.

  • Bohemian
    Bohemian about 10 years
    I always use neither - I use default (ie omit) visibility, because it's one less word to type and read in the code.
  • chain ro
    chain ro about 10 years
    Declaring a field as private will let the compiler inserts package private methods, is it right?
  • Seelenvirtuose
    Seelenvirtuose about 10 years
    Yes and no. The compiler must enforce that no private field is access from outside the class. But he also must consider the JLS (I quoted). So the trick is to automatically add package private methods, which now can be accessed from outside the class. These methods are placed in the inner class, but only if needed, i.e. if there is indeed access like in this example. Additionally, all direct accesses to that private field are exchanged with calls to those methods.
  • masT
    masT almost 7 years
    @Seelenvirtuose, what issues can be there if LazyHolder doesn't make INSTANCE as final