Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

It seems that I can *reference a field before it is defined*

public enum MyEnum1 {

    FOO(BAR), BAR(FOO);

    private MyEnum1 other;

    private MyEnum1(MyEnum1 other) {
        this.other = other;
    }

    public MyEnum1 getOther() {
        return other;
    }

}

MyEnum1 generates the error Cannot reference a field before it is defined, which is quite understandable, since declaration order matters here. But why does the following compile?

public enum MyEnum2 {

    FOO { public MyEnum2 getOther() { return BAR; } },
    BAR { public MyEnum2 getOther() { return FOO; } };

    public abstract MyEnum2 getOther();

}

FOO refers to BAR before BAR is defined, am I wrong?

like image 291
sp00m Avatar asked Oct 03 '22 04:10

sp00m


2 Answers

The important JLS parts are this and this

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

T is a class and an instance of T is created.

T is a class and a static method declared by T is invoked.

A static field declared by T is assigned.

A static field declared by T is used and the field is not a constant variable (§4.12.4).

T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

And

The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type.

So with

FOO { public MyEnum2 getOther() { return BAR; } }, 
BAR { public MyEnum2 getOther() { return FOO; } };

you are creating two anonymous classes extending MyEnum2.

When BAR is eventually reference either when you call Foo.getOther() or some other piece of code does MyEnum2.Bar, the type will be initialized.

like image 103
Sotirios Delimanolis Avatar answered Oct 07 '22 22:10

Sotirios Delimanolis


you are creating enum constant with reference to yet undeclared constant in first case. In second case it does not matter because of compilation order, enumeration constants are compiled before enumeration body. I would say this is the reason. If it was not true, compilation would fail earlier because abstract method declaration is defined after the non-abstract method declaration in body of each enum constant.

Good reference - http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9

like image 36
Jan Hruby Avatar answered Oct 07 '22 23:10

Jan Hruby