为什么我可以匿名地子类化枚举而不是最终的类?

问题描述:

这段代码:

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);
    }
}

打印:


我是值

I'm the value

但是,这段代码:

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";
            }
        });
    }
}

导致编译错误:

cannot inherit from final HelloWorld.C

为什么可以 E.VALUE 创建我看起来是一个匿名的 E 子类,覆盖 toString 方法,而使用最终类而不是隐式最终枚举会引发编译时错误?

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?

更多具体来说,为什么可以 VALUE 覆盖 E 中的任何内容?我的印象是代码

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

public enum E {
    VALUE;
}

大致相当于

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?

根据

According to the JLS:


枚举类型是隐式最终的,除非它包含至少一个具有类体的枚举
常量。

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

您的示例 VALUE 有一个类体,因此 E 不是隐式最终的。

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

编辑以下是一个验证声明的快速示例:

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()));
  }
}

您可以从输出中看到编译器正在添加最终修饰符到 E2 但不是 E

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

编辑#2:
即使 E 不是 final 并且被 VALUE 子类化,明确地尝试扩展它,例如与类Foo扩展E 枚举栏扩展E 是根据 8.1.4。超类和子类

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:


如果ClassType命名了类Enum或
任何一个编译时错误调用它。

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