-1

i've been taught that in java static init block will be called before any instance of object will be created, but I faced a situation while playing with old singleton pattern (not to discuss why it's good or bad pattern). In the example below i have two implementations of lazy singleton and second breaks order in which ctor & static init blocks are called.

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SingletonDemo {


    static class demo1 {
        static class SingletonHolder {
            static final Singleton INSTANCE = new Singleton();
        }

        static class Singleton {
            public static Singleton instance() {
                return SingletonHolder.INSTANCE;
            }

            static {
                log.info("Singleton1$static");
            }

            public Singleton() {
                log.info("Singleton1$init");
            }
        }
    }

    static class demo2 {
        static class SingletonHolder {
            public static Singleton instance() {
                return Singleton.INSTANCE;
            }
        }

        static class Singleton {
            static final Singleton INSTANCE = new Singleton();

            static {
                log.info("Singleton2$static");
            }

            public Singleton() {
                log.info("Singleton2$init");
            }
        }
    }

    public static void main(String[] args) {
        demo1.Singleton.instance();
        demo2.SingletonHolder.instance();
    }

}

and output is as follows:

04:50:36.815 [main] INFO SingletonDemo - Singleton1$static
04:50:36.831 [main] INFO SingletonDemo - Singleton1$init
04:50:36.831 [main] INFO SingletonDemo - Singleton2$init
04:50:36.831 [main] INFO SingletonDemo - Singleton2$static

so the question is why ?

  • "Static initializers run before any instance initializers" is a bit of an oversimplification. The correct phrasing is close to: "class initialization is triggered before any object of that class can be created, but might not be finished when the first instances are created". – Joachim Sauer Oct 24 '21 at 14:02

2 Answers2

2

Static fields with initializers and static blocks are executed in their textual order (see JLS, §12.1.3). Hence, the constructor call

static final Singleton INSTANCE = new Singleton();

is executed before the static initializer block.

Turing85
  • 18,217
  • 7
  • 33
  • 58
-1

I am beginning slowly understand why (of course Java spec is absolutely right - static block is called before ctor) and order of initialization is not fields and then static init block, problem here is that log messages give wrong impressions on what happens, let's change order of second example a bit


static class Singleton {
            static {
                log.info("Singleton2$static#1");
            }

            static final Singleton INSTANCE = new Singleton();

            static {
                log.info("Singleton2$static#2");
            }

            public Singleton() {
                log.info("Singleton2$init");
            }
        }
    }


Then it works as expected

05:16:18.130 [main] INFO SingletonDemo - Singleton2$static#1
05:16:18.130 [main] INFO SingletonDemo - Singleton2$init
05:16:18.130 [main] INFO SingletonDemo - Singleton2$static#2

I think Java combined all static blocks and field init into one giant static block which is really being executed before anything else - but in the middle of it I need to create instance of object and I do it - even though static init block is not completed yet

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • As I have remarked in my answer, the behaviour is well-defined in the JLS and this has nothing to do with the logging. [JLS, §12.1.3](https://docs.oracle.com/javase/specs/jls/se17/html/jls-12.html#jls-12.1.3) clearly states that static initializers and static blocks are executed in textual order. – Turing85 Oct 24 '21 at 12:20