11

This code:

public class Sandbox {
    public enum E {
        VALUE {
            @Override
            public String toString() {
                return "I'm the value";
            }
        };

        @Override
        public String toString() {
            return "I'm the enum";
        }
    }
    public static void main(String[] args) {
        System.out.println(E.VALUE);
    }
}

prints:

I'm the value

However, this code:

public class Sandbox {
    public static final class C {
        @Override
        public String toString() {
            return "I'm a C";
        }
    }

    public static void main(String[] args) {
        System.out.println(new C() {
            @Override
            public String toString() {
                return "I'm anonymous";
            }
        });
    }
}

results in a compilation error:

cannot inherit from final HelloWorld.C

Why can E.VALUE create what appears to me to be an anonymous E subclass, overriding the toString method, while using a final class instead of an implicitly final enum throws a compile-time error?

More specifically, why can VALUE override anything in E? I was under the impression that the code

public enum E {
    VALUE;
}

was roughly equivalent to

public static final class E {
    public static final E VALUE = new E();
}

in which case the anonymous nature would not be allowed.

What's the difference? Why are enums special?

wchargin
  • 15,589
  • 12
  • 71
  • 110
  • 3
    Can't tell the reason, but JLS7 states that _The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes; in particular it cannot contain any constructors._ Perhaps, intention was to give developer extra flexibility when defining enum's constants – Victor Sorokin Jun 06 '13 at 19:36
  • Enums have been designed that way to serve special programming purposes not covered by this answer. – Piovezan Jun 06 '13 at 19:36
  • Because enums in Java are... special. You said roughly yourself. If someone would write out the idea behind the reasoning that would be great, of course. +1 still for an interesting snippet. – zw324 Jun 06 '13 at 19:40
  • @ZiyaoWei there's nothing *special*, there are always rules to backup the design of the language. – Luiggi Mendoza Jun 06 '13 at 19:44
  • @LuiggiMendoza well, special as in "JLS has a chapter for it, rather than treating it as just another everyday class"? But I agree, nothing in Java is special if all the rules are not considered special (JLS is simply too comprehensive). What I tried to say was that Enums are not normal classes, although damo's answer somewhat proved me wrong in this certain context (since it is behaving rather like a mundane class). – zw324 Jun 06 '13 at 19:45
  • @ZiyaoWei mundane `static` class (if is not top `enum`). – Luiggi Mendoza Jun 06 '13 at 19:49

3 Answers3

16

According to the JLS:

An enum type is implicitly final unless it contains at least one enum constant that has a class body.

In your example, VALUE has a class body and therefore E is not implicitly final.

Edit: Here's a quick example that validates the claim:

import java.lang.reflect.Modifier;

public class Sandbox {
  public enum E {
    VALUE {};
  }

  public enum E2 {
    VALUE;
  }

  public static void main(String[] args) {
    System.out.println(E.class);
    System.out.println(E.VALUE.getClass());
    System.out.println("E.VALUE is subclass of E = " + E.VALUE.getClass().getSuperclass().equals(E.class));
    System.out.println("E modifiers: " + Modifier.toString(E.class.getModifiers()));
    System.out.println("E2 modifiers: " + Modifier.toString(E2.class.getModifiers()));
  }
}

You can see from the output that the compiler is adding the final modifier to E2 but not to E:

class Sandbox$E
class Sandbox$E$1
E.VALUE is subclass of E = true
E modifiers: public static
E2 modifiers: public static final

Edit #2: Even though E is not final and is subclassed by VALUE, explicitly trying to extend it such as with class Foo extends E or enum Bar extends E is a compile-time error according to 8.1.4. Superclasses and Subclasses:

It is a compile-time error if the ClassType names the class Enum or any invocation of it.

DannyMo
  • 11,344
  • 4
  • 31
  • 37
  • In the OP's example, `VALUE`'s class is an anonymous subclass of `E`. `System.out.println(E.VALUE.getClass())` will output something like `E$1` and `E.VALUE.getClass().getSuperclass().equals(E.class) == true` – DannyMo Jun 06 '13 at 21:53
  • @WChargin updated with additional info. Long story short: because the JLS says so =) – DannyMo Jun 07 '13 at 02:29
  • +1 for quoting "An enum type is implicitly final unless it contains at least one enum constant that has a class body." @DannyMo it might make sense to also show in your example that E2.VALUE is not a anonymous subclass of E2 rather an instance of E2 ,in other words, `E2.VALUE.getClass().getSuperclass().equals(E2.class)` will return false. – sactiw Jun 11 '15 at 08:54
5

I think if you compare classes and enums, then the enum E can be compared to a class, and the enum value VALUE can be compared to an anonymous instance. Thus, your first example can be rewritten as following:

public class Sandbox {
    public static class E {
        public static final E VALUE = new E() {
            @Override
            public String toString() {
                return "I'm the value";
            }
        };

        @Override
        public String toString() {
           return "I'm the enum";
       }
    }
    public static void main(String[] args) {
        System.out.println(E.VALUE);
    }
}

funkygono
  • 426
  • 3
  • 5
2

If you take the following into account, your concern may be lessened:

A class which has no non-private constructor is effectively final since it is impossible to declare its subclass outside of its body. It is a minor technical detail whether the class defined by an enum is declared final or not: it will in either case be effectively final.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436