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

时间:2013-06-06 19:31:35

标签: 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() {
            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();
}

在这种情况下,不允许使用匿名性质。

有什么区别?为什么枚举很特别?

3 个答案:

答案 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 Eenum 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是一个次要的技术细节:在任何一种情况下,它都将有效地最终