【问题标题】:Why does casting an enum to any interface not cause a compilation error in Java when the enum type contains at least one "extended" enum?当枚举类型包含至少一个“扩展”枚举时,为什么将枚举转换为任何接口都不会导致 Java 中的编译错误?
【发布时间】:2020-10-14 14:32:56
【问题描述】:

以下代码编译:

    public enum Foo {
        A,
        B{};
        public static void main(String[] args) {
            Foo f = Foo.A;
            List s = (List)f;
        }
    }

这个没有:

public enum Foo {
        A,
        B;
        public static void main(String[] args) {
            Foo f = Foo.A;
            List s = (List)f;
        }
    }

我也可以用Foo.B 替换Foo.A 并得到相同的结果。 这里发生了什么?在第一个示例中,Foo.A 怎么可能是 List

【问题讨论】:

  • 我猜编译器的原因是因为你的枚举确实有子类型,所以它可能有一个实现接口的子类型;即使它实际上没有。
  • 我尝试编译您的第一个示例,但它不起作用(将枚举设为非公开并将 main 移动到单独的公共类)。编辑。它编译但在执行期间抛出ClassCastException
  • @Amongalen 是的,这就是重点。总会有一个ClassCastException,我不明白为什么编译器不知道:)
  • @khelwood 据我所知,Java 中的enum 不能从其他类型继承。
  • @HansWurst 实际上,我认为枚举可以实现接口,只是不能扩展类,因为它们已经扩展了Enum

标签: java enums compiler-errors compilation


【解决方案1】:

对于这种类型的转换,spec on Narrowing Reference Conversion 定义了规则。枚举没有特殊情况,只有最终类和非最终类之间的区别。

基本枚举属于“最终类”类别,但您的扩展枚举不属于,因为它通过{} 语法引入了一个子类。

当然,即使使用扩展枚举,您的枚举常量之一也不可能实现List,但当前规范根本没有涵盖这种情况。

规范的未来修订版可能会改进这一点,然后我希望编译器能够实现额外的检查。但目前,这种程度的编译时安全性不可用。

【讨论】:

  • 嗯,这很令人惊讶,因为javap Foo.class 给了我public class Foo extends java.lang.Enum<Foo> { ... } 两者。
  • @HansWurst 我猜有人可以在在运行时向该枚举添加一个接口。
  • @HansWurst there you go...
  • @Eugene 有可能(参见我之前的评论),但我认为 Java 语言设计者在定义规则时没有考虑到这种可能性。只是没有考虑为 enum 类型添加特殊规则,因此现有规则的组合导致了我们在此处看到的行为。
猜你喜欢
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 2023-02-21
  • 1970-01-01
  • 2010-12-10
  • 2010-10-11
相关资源
最近更新 更多