Java 为什么我可以匿名地将枚举子类化,而不是最终类?
此代码:Java 为什么我可以匿名地将枚举子类化,而不是最终类?,java,enums,anonymous-types,final,Java,Enums,Anonymous Types,Final,此代码: public class Sandbox { public enum E { VALUE { @Override public String toString() { return "I'm the value"; } }; @Override public String toString() {
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类而不是隐式final枚举抛出编译时错误
更具体地说,为什么VALUE
可以覆盖E
中的任何内容?我的印象是
public enum E {
VALUE;
}
大致相当于
public static final class E {
public static final E VALUE = new E();
}
在这种情况下,匿名性质是不允许的
有什么区别?为什么枚举是特殊的?根据:
除非枚举类型至少包含一个枚举,否则它是隐式最终类型
具有类主体的常量
在您的示例中,VALUE
有一个类主体,因此E
不是隐式的final
编辑:下面是一个验证声明的快速示例:
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
是编译时错误,根据:
如果类类型将类命名为Enum或
任何对它的调用
我认为如果比较类和枚举,那么枚举E可以与类比较,枚举值可以与匿名实例比较。因此,您的第一个示例可以改写如下:
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);
}
}
如果您考虑以下因素,您的担忧可能会减少:
没有非私有构造函数的类实际上是最终类,因为不可能在其主体之外声明其子类。由
enum
定义的类是否声明为final
是一个次要的技术细节:在任何一种情况下,它都将是有效的final。无法说明原因,但JLS7声明enum常量的可选类体隐式定义了匿名类声明(§15.9.5)它扩展了立即封闭的枚举类型。类主体由匿名类的常规规则管理;特别是它不能包含任何构造函数。也许,其目的是在定义enum的constantsEnums时给开发人员额外的灵活性,因为enum的constantsEnums是以这种方式设计的,以服务于本答案未涉及的特殊编程目的。。。特别的。你说的很粗鲁。当然,如果有人能写出推理背后的想法,那就太好了+1还有一个有趣的片段。@ZiyaoWei没有什么特别的,总是有规则来备份语言的设计。@LuiggiMendoza很好,特别是在“JLS有一章介绍它,而不是把它当作另一个日常类”?但是我同意,如果所有规则都不被认为是特殊的,那么Java中没有什么是特殊的(JLS太全面了)。我想说的是枚举不是普通类,尽管damo的回答在某种程度上证明了我的错误(因为它的行为相当像一个普通类)。在OP的例子中,VALUE
的类是E
的匿名子类System.out.println(E.VALUE.getClass())
将输出类似E$1
和E.VALUE.getClass().getSuperclass().equals(E.class)==true
@WChargin的内容,并用其他信息更新。长话短说:因为JLS说so=)+1引用“枚举类型是隐式最终的,除非它至少包含一个具有类主体的枚举常量。”@DannyMo在您的示例中还可以说明E2.VALUE不是E2的匿名子类,而是E2的实例,换句话说,E2.VALUE.getClass().getSuperclass().equals(E2.class)
将返回false。从未想过这样!