19

Given the following enum:

enum Repeat {
    Daily,
    Weekly,
    Yearly
}

I realize we are able to write it this way:

Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;

which is equivalent to:

Repeat repeat = Repeat.Weekly;

May I know why such syntax is allowed? Is there a way to let the compiler warn us against this?

Boann
  • 48,794
  • 16
  • 117
  • 146
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • `Is there a way to let compiler warn us against this?` you should configure [Linter](https://stackoverflow.com/a/14692135/3872976) for that. – deathangel908 May 26 '18 at 19:07
  • ["If the field is `static`: The *Primary* expression is evaluated, and the result is discarded. \[...\] The result \[of the field access expression\] is the value of the specified class variable in the class or interface that is the type of the *Primary* expression."](https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.11.1) – Radiodef May 26 '18 at 21:27

4 Answers4

19

This is allowed as Daily, Weekly, Yearly are the static field by default inside the enum and holds the object of Repeat. Also, you will get a warning from the compiler "The static field Repeat.Weekly should be accessed in a static way". It is similar to below lines of code.

class Foo{
    public static Foo obj1 = new Foo();
    public static Foo obj2 = new Foo();
    public static Foo obj3 = new Foo();
}

Foo f = Foo.obj1.obj2.obj3; // will work fine but you will get a warning from the compiler.

Here is some part of bytecode inspection of Repeat enum and from this, it is clear that Enum variable is static and holds the Object of Enum itself.

   0: new           #1                  // class com/java8/demo/Repeat
   3: dup
   4: ldc           #14                 // String Daily
   6: iconst_0
   7: invokespecial #15                 // Method "<init>":(Ljava/lang/String;I)V
  10: putstatic     #19                 // Field Daily:Lcom/java8/demo/Repeat;
  13: new           #1                  // class com/java8/demo/Repeat 
Amit Bera
  • 7,075
  • 1
  • 19
  • 42
5

Enum instance are just static instance of the enum class.

We have two way to access static field of a class:

  1. Via class itselft: Repeat.Daily
  2. Via instance of class: Repeat.Daily.Daily

When you chain your enum:

Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;

It's just like get a static field from an instance of a class.

Mạnh Quyết Nguyễn
  • 17,677
  • 1
  • 23
  • 51
2

Is there a way to let compiler warn us against this?

Yes, use a good IDE and turn on warning. That way, you'll be notified as soon as your write the code, before you even compile it.

E.g. in Eclipse, it is called "Non-static access to static member":

enter image description here

Andreas
  • 154,647
  • 11
  • 152
  • 247
1

Enum literals are static members, and with each static member, one can access them either using the class reference:

TypeName.staticMember
TypeName.staticMethod()

Or on an instance:

new TypeName().staticMember
new TypeName().staticMethod()

The second approach is discouraged (and the compiler will issue a warning)

As enum literals are just static members, Repeat.Daily.Weekly.Yearly.Weekly is like the second code snippet above, accessing static members on instance references.

With a class, that would be:

class Type {
    static Type INSTANCE1, INSTANCE2, INSTANCE3;
}

And one can get a reference to INSTANCE3 using Type.INSTANCE1.INSTANCE2.INSTANCE3. It's valid, but it's bad practice.

ernest_k
  • 44,416
  • 5
  • 53
  • 99