3

Accessing static variables in constructor of enum class is forbidden in java. Why in enumerations the order of static initialization is not swapped?

Example of correct code:

enum Test
{
    TEST1, TEST2;

    static int x;
}

Why do developers of java did not created such code as correct:

enum Test
{
    static int x;

    TEST1, TEST2;
}

Then static variables could be used in constructor. Now it is forbidden.

Does it have any reason or it is just their design?

Pawel
  • 1,457
  • 1
  • 11
  • 22
  • 2
    "*Accessing static variables is forbidden in Java*" - What do you mean by this? – PM 77-1 Oct 20 '13 at 23:39
  • @PM77-1 See edit. The sentence was unclear. – Pawel Oct 20 '13 at 23:41
  • 1
    @JamesMontagne I know why `static` variables cannot be used in costructor. I want to know why do developers and architects of java did not changed the order of initialization. – Pawel Oct 20 '13 at 23:43
  • In that case I would probably consider this question "primarily opinion based" http://meta.stackexchange.com/questions/10582/what-is-a-closed-or-on-hold-question/10583#10583 – James Montagne Oct 20 '13 at 23:50
  • If there is reason, then it is not opinion-based. If there is no reason, the answer is: "there is no reason, it is just their design", the topic can be closed. – Pawel Oct 20 '13 at 23:55
  • Maybe it is because if people could put enum constants anywhere it would be possible to use static fields inside constructors. This would still be dangerous because people could still put constants at start of enum. To prevent it we are made to put them at start and we cant use static fields inside constructor. But that is just a guess. – Pshemo Oct 21 '13 at 00:05
  • I thought that anybody will know the reason. I thought that it is connected with construction problems. – Pawel Oct 21 '13 at 00:09
  • @Pawel check the "update" I added to my answer - maybe that will help explaining it better – Nir Alfasi Oct 21 '13 at 00:26
  • I understand, but I wonder why it is in that manner. `enum` is like normal class, but in opposite to normal classes static field cannot be accessed from constructors. It could be accessed with different design of that class. Then also static block would not be needed. – Pawel Oct 21 '13 at 07:30

2 Answers2

5

Well, it's to ensure safe instance initialization - the enum instances are very similar to static final instances of the enum class, and the language has defined that they be initialized first.

But if you know a trick or two you can effectively use static variables in an enum constructor:

enum Test {
    TEST1, TEST2;

    static class Holder {
        static int x;
    }

    Test() {
        Holder.x++; // no compiler error
    }
}

For more info see Initialization-on-demand holder idiom

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 1
    Ok, but if initialization of `TEST1` and `TEST2` would be moved on the end of the class then we do not to have to do tricks. I want to know why the initialization order is as such. – Pawel Oct 20 '13 at 23:47
1

From JLS (§8.9):

An enum declaration specifies a new enum type


EnumDeclaration: ClassModifiersopt enum Identifier Interfacesopt EnumBody

EnumBody: { EnumConstants-opt ,opt EnumBodyDeclarations-opt }


As you can see, the body should be defined with enum-constants declared first and other body declarations may follow - not the other way around!

Further, you don't have to use lazy initialization like bohemian suggested you can do it in a simpler manner. According to JLS you can't do:

enum Test {
    TEST1, TEST2;
    static int x;

    Test(){
        x = 1; // <-- compilation error!
    }
}

but you can use static initializer block:

enum Test {
    TEST1, TEST2;
    static int x;

    static{
        x = 1; // works!
    }
}

The reason that you CAN use the latter is that static declarations are executed in the same order they were declared - assigning x=1 will occur only after x was declared, unlike using a constructor. If you want to verify it - you can add System.out.println() calls to the constructor and static block - you'll see that the constructor is being executed first.

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • 1
    OP knows that. Question is why it is designed this way. – Pshemo Oct 20 '13 at 23:54
  • Exactly. I know the construction and I want to know the reason of this construction, because my second construction would be also correct (not compiled by compiler, but able to execute). – Pawel Oct 20 '13 at 23:57
  • 1
    @Pshemo the OP asked "Does it have any reason or it is just their design?", and my answer shows him that it was designed to work this way. As for the philosophical reason of "why" he'll have to ask Gosling, but a good guess will be that since `Enum` [*initialization rules*](http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2) are different than "normal" class (i.e. static initializer vs. constructor) - it only made sense to decide on an order which will make sense. – Nir Alfasi Oct 20 '13 at 23:58