为了测试一些东西,我尝试制作一个枚举,其中枚举中的每个元素都有一个不同的类。
举个例子:
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
内部类也是可能的。正式规则是相关的,虽然乍一看它看起来像是预期的行为,但令人惊讶的是它并没有以这种方式得到规范的支持。
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 classes和 enum
constant bodies ;它们都指向 §8.1.6 的“类主体”。考虑到这一点,我们的类是“成员类”,因为它们包含在类主体中。
现在我们可以尝试将其解释为错误的交叉引用,假设“另一个类的主体......声明”是指Class Declarations ,即使用 class
关键字的命名类声明,但是,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
类或您的 First
和 Second
类。它们没有放在一个 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/