5

My sample enum Singleton class is:

public class Test{

    public enum MyClass{

        INSTANCE;

        private static String name = "Hello";

        MyClass() {
            test();
        }

        private static void test(){
            name = name + "World";
            System.out.println(name);
        }
    }

    public static void main(String a[]){

        MyClass m1 = MyClass.INSTANCE; 

    }
}

Obtained output : nullWorld
Expected output : HelloWorld

In main(), if

MyClass m1 = MyClass.INSTANCE;

is replaced by

MyClass.INSTANCE.test();

then, the output is HelloWorld, as expected.

This shows that static fields are not initialized until the constructor has completed execution.

Question : How to achieve this functionality of calling a method within constructor that accesses static fields?

Aadhirai R
  • 141
  • 9
  • Check this: https://stackoverflow.com/questions/443980/why-cant-enums-constructor-access-static-fields – ernest_k Nov 15 '18 at 05:03
  • 2
    @AadhiraiR the whole point of singleton ist to have a single instance that can hold state - why do you need a static variable in a singleton? Just make it an instance variable instead. – Hulk Nov 15 '18 at 07:24
  • @Hulk, true! I realized that and am removing all the static fields in the enum singleton class. – Aadhirai R Nov 15 '18 at 09:18

1 Answers1

3

This is because INSTANCE is declared before name, so it is created and initalized before name is initialized.

This works:

public enum MyClass{
    INSTANCE;
    private static final String name = "Hello";

    MyClass() {
        test();
    }

    private static void test(){
        String name1 = name + "World";
        System.out.println(name1);
    }
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • 1
    Why does it work by making `name` final? Are `final static` variables initialized before `static` variables even if they are declared after? – Kartik Nov 15 '18 at 04:36
  • My requirement is to have a static variable that is not final. I want to be able to modify it. – Aadhirai R Nov 15 '18 at 04:50
  • I know Josh Bloch has suggested this way to implement Singleton pattern in his Effective Java book. But when this approach doesn't work then one should fall back to old approach of making a singleton via class implementation where you can define the name variable before the INSTANCE variable and then not keep it final but still you get your expected output! Is there any force that you have to implement singleton via enum only? – Ketan Nov 15 '18 at 05:33
  • 1
    @Aadhirai R if it were not enum you could move name before INSTANCE then it would work. – Evgeniy Dorofeev Nov 15 '18 at 05:37
  • 4
    @Kartik Making it `final` changes things because the variable is now a [_compile-time constant_](https://stackoverflow.com/questions/9082971/compile-time-constants-and-variables?rq=1). This means the compiler replaces the use of `name` within `test()` with the constant value of `name`. Since this happens at compile-time there is no issue with the order of initialization. – Slaw Nov 15 '18 at 09:06
  • @Ketan : Via class implementation, there is no guarantee that the public methods would not be called before instantiation using a getInstance() method. Right? – Aadhirai R Nov 15 '18 at 09:10
  • @AadhiraiR I am not sure what exactly do you mean by public methods here? If they are non-static methods, then no one can invoke them anyways without instance! Declare the variable as "private static final Singleton INSTANCE = new Singleton();" so you don't have risk of double instance by any means. This should give you your desired results – Ketan Nov 15 '18 at 23:22
  • @Slaw thank you, that explains it.. didn't know about compile-time constants – Kartik Nov 15 '18 at 23:27