此代码:
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);
}
}
打印:
我是价值
但是,这段代码:
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
方法,而使用final类而不是隐式最终枚举会抛出编译 - 时间错误?
更具体地说,为什么VALUE
可以覆盖E
中的任何内容?我的印象是代码
public enum E {
VALUE;
}
大致相当于
public static final class E {
public static final E VALUE = new E();
}
在这种情况下,不允许使用匿名性质。
有什么区别?为什么枚举很特别?
答案 0 :(得分:16)
根据JLS:
枚举类型是隐式最终的,除非它包含至少一个枚举 具有类体的常数。
在您的示例中,VALUE
有一个类主体,因此E
不是隐式最终的。
修改:以下是验证声明的简单示例:
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()));
}
}
您可以从输出中看到编译器正在将final
修饰符添加到E2
但不会添加到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
进行了子类化,也明确尝试对其进行扩展,例如class Foo extends E
或enum Bar extends E
是根据8.1.4. Superclasses and Subclasses的编译时错误:
如果ClassType将类命名为Enum或,则为编译时错误 任何调用它。
答案 1 :(得分:5)
我认为如果你比较类和枚举,那么可以将枚举E与类进行比较,并且可以将枚举值VALUE与匿名实例进行比较。因此,您的第一个示例可以重写如下:
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);
}
}
答案 2 :(得分:2)
如果您考虑以下因素,您的担忧可能会减轻:
没有非私有构造函数的类是有效的最终,因为无法在其正文之外声明其子类。由enum
定义的类是否被声明为final
是一个次要的技术细节:在任何一种情况下,它都将有效地最终。