Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么我可以匿名地将枚举子类化,而不是最终类?_Java_Enums_Anonymous Types_Final - Fatal编程技术网

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。从未想过这样!