java - 为什么我不能公开枚举的内部类?

标签 java enums java-8

为了测试一些东西,我尝试制作一个枚举,其中枚举中的每个元素都有一个不同的类。

举个例子:

public enum MyEnum {

    first{
        class First{}
    },
    second {
        class Second{}
    };
}

如果我尝试在任何类之前放置一个公共(public)修饰符,此处不允许的修饰符就会出现。我不太确定为什么会这样。我无法在枚举之外实例化这些类,也看不到它们。但是我可以设法让一个实例这样做:

public enum MyEnum {

    first{
        class First{}

        public Object getObject(){
            return new First();
        }
    },
    second {
        class Second{}

        public Object getObject(){
            return new Second();
        }
    };

    public abstract Object getObject();
}


public class Main {
    public static void main(String[] args) {
        System.out.println(MyEnum.first.getObject().getClass());
        System.out.println(MyEnum.second.getObject().getClass());
    }
}

输出:

class MyEnum$1$First

class MyEnum$2$Second

明明可以引用这个类,为什么编译时不能访问呢?

最佳答案

TL;DR 这已通过 JDK 16 修复

JDK 16 更改了规则,现在允许内部类拥有 static 成员。似乎这个问题的问题已被修复为副作用。由于这也应该是早期版本中的行为,因此 public 被 JDK 16+ 编译器接受,即使 --release 8 也是如此。

这是一个非常有趣的问题。您将无法在编译时访问这些类,即使允许使用 public 修饰符,因为它们包含在隐式匿名类中,所以无论如何都不能通过名称访问它们(除了在匿名类中)。您不能通过变量访问类型,即访问 MyEnum.first.First 在 Java 中根本不可能。

仍然,没有用并不一定决定可以声明什么,即在 private 外部类中声明一个 public 内部类也是可能的。正式规则是相关的,虽然乍一看它看起来像是预期的行为,但令人惊讶的是它并没有以这种方式得到规范的支持。

JLS §8.9.1, Enum Constants状态:

The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes…

这给了我们一个有趣的提示,即

class Outer {
    static Object o = new Object() {
        public class Inner {
        }
    };
}

在 JDK 16 之前被编译器拒绝。

考虑JLS, §8.1.1. Class Modifiers :

The access modifier public (§6.6) pertains only to top level classes (§7.6) and member classes (§8.5), not to local classes (§14.3) or anonymous classes (§15.9.5).

我们必须决定 Inner 或您的 First 类别属于哪个类别。这与他们周围的类是匿名类这一事实无关。显然,它们既不是顶级类也不是匿名类,因为它们是嵌套的并且有一个名字。因此它们必须是成员类(public 允许)或本地类(public 不允许)。

JLS, §8.5. Member Type Declarations :

A member class is a class whose declaration is directly enclosed in the body of another class or interface declaration (§8.1.6, §9.1.4).

“另一个类的主体……声明”是通过指向 §8.1.6 定义的它确实定义了 ClassBody 语言语法,named declarations 常用它, anonymous classesenum constant bodies ;它们都指向 §8.1.6 的“类主体”。考虑到这一点,我们的类是“成员类”,因为它们包含在类主体中。

现在我们可以尝试将其解释为错误的交叉引用,假设“另一个类的主体......声明”是指Class Declarations ,即使用 class 关键字的命名类声明,但是,local classes 的定义反驳了这种解释。

JLS §14.3, Local Classes :

A local class is a nested class (§8 (Classes)) that is not a member of any class and that has a name (§6.2, §6.7).

Every local class declaration statement is immediately contained by a block (§14.2). Local class declaration statements may be intermixed freely with other kinds of statements in the block.

“ block ”实际上是指像非抽象 方法、构造函数或初始化程序(§14.2)的定义那样的 block 。这不适用于上面的 Inner 类或您的 FirstSecond 类。它们没有放在一个 block 中,也不能与该上下文中的语句自由混合,因为此时不允许语句。

换句话说,它们绝对不是本地类,并且假设没有规范未描述的另一类类,我们必须将它们视为成员类,作为当前的编写和链接成员类的定义也表明,换句话说,根据引用的规则,public 修饰符应该允许在这个地方

为了完整起见,这里是匿名类的定义,只是为了表明没有异常(exception)规则说他们的成员类不允许是public:

15.9.5. Anonymous Class Declarations

An anonymous class declaration is automatically derived from a class instance creation expression by the Java compiler.

An anonymous class is never abstract (§8.1.1.1).

An anonymous class is always implicitly final (§8.1.1.2).

An anonymous class is always an inner class (§8.1.3); it is never static (§8.1.1, §8.5.1).

最后一点暗示反过来,它们的成员类也不能是static,但是,没有规则禁止它们是public

关于java - 为什么我不能公开枚举的内部类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43772759/

相关文章:

java - MANIFEST.MF 中的Class-Path 是否只能包含jar 文件?

java - 完全 volatile 可见性保证

mysql - 将多个 "attributes"添加到 MySQL 数据库中的身份的最有效方法

swift - 覆盖子类中的枚举情况

objective-c - 我可以检索枚举/类型中所有项目的列表吗?

java - Hibernate EntityListeners - PrePersist 方法在持久调用之前修改模型 - 如果持久调用失败怎么办?

java - 使用 printf() java 比较 2 个数字

java - map.foreach java8 中的条件和

java - 映射时处理重复的键

java - 使用流收集器从 java 对象获取键值