测试了一些东西,我试着制作一个枚举,其中枚举中的每个元素都有不同的类。
以例如:
public enum MyEnum {
first{
class First{}
},
second {
class Second{}
};
}
如果我尝试在任何类之前放置一个公共修饰符,则此处不允许使用修饰符。我不太清楚为什么会这样。我不能在枚举之外实例化这些类,也不能看到它们。但是我可以设法让实例这样做:
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
我可以清楚地引用这个类,为什么我不能在编译时访问它?
答案 0 :(得分:4)
这是一个非常有趣的问题。即使允许public
修饰符,您也无法在编译时访问这些类,因为它们包含在隐式匿名类中,因此无论如何都无法通过名称访问它们(除了匿名之外)类)。您无法通过变量访问类型,即在Java中根本无法访问MyEnum.first.First
。
但是,没有用是不一定确定可以声明的内容,即在public
外部类中声明private
内部类也是可能的。正式规则是相关的,虽然它看起来像乍看之下的预期行为,但令人惊讶的是它没有以这种方式支持规范。
枚举常量的可选类主体隐式定义了一个匿名类声明(§15.9.5),它扩展了直接封闭的枚举类型。班级团体由匿名班级的通常规则管理......
给了我们一个有趣的提示,即
class Outer {
static Object o = new Object() {
public class Inner {
}
};
}
被编译器拒绝。
考虑JLS, §8.1.1. Class Modifiers:
访问修饰符
public
(§6.6)仅适用于顶级类(§7.6)和成员类(§8.5),而不属于本地类({{3} }}或匿名类(§14.3)。
我们必须决定哪个类别Inner
或您的First
类失败。这并不是因为他们周围的班级是一个匿名班级。显然,它们既不是顶级类也不是匿名类,因为它们是嵌套的并且具有名称。所以它们必须是,成员类(允许public
)或本地类(public
不允许)。
成员类是一个类,其声明直接包含在另一个类或接口声明(JLS, §8.5. Member Type Declarations,§8.1.6)的主体中。
“另一个类......声明的主体”是通过指向§9.1.4来定义的,§8.1.6确实定义ClassBody
语言语法,named declarations常用,anonymous classes和enum
constant bodies;所有这些都指向§8.1.6的“阶级主体”。考虑到这一点,我们的类是“成员类”,因为它们包含在类体中。
现在我们可以尝试将其解释为错误的交叉引用,假设“另一个类的主体...... 声明”意味着引用Class Declarations,即命名类声明使用class
关键字,但本地类的定义反驳了这种解释。
本地类是一个嵌套类(§8 (Classes)),它不是任何类的成员,并且具有名称(§6.2,§6.7)
...
每个本地类声明语句都会立即被一个块(§14.2)包含。本地类声明语句可以与块中的其他类型的语句自由混合。
“Block”实际上意味着块类似于非abstract
方法,构造函数或初始值设定项(§14.2)的定义。这不适用于上面的Inner
课程或您的First
和Second
课程。它们不是放在一个块中,也不能在该上下文中与语句自由混合,因为此时不允许声明。
换句话说,它们肯定不是本地类,并且假设没有其他类没有规范描述的类,我们必须将它们视为成员类,作为当前的编写和链接成员类的定义也表示,换句话说,根据引用的规则,应该允许public
修饰符在这个地方。
为了完整性,这里是匿名类的定义,只是为了表明没有例外规则说他们的成员类不允许public
:
15.9.5. Anonymous Class DeclarationsJava编译器会自动从类实例创建表达式派生出一个匿名类声明。
匿名类永远不会是
abstract
(§8.1.1.1)。匿名类总是隐式
final
(§8.1.1.2)。匿名类始终是内部类(第8.1.3节);它永远不会
static
(§8.1.1,§8.5.1)。
最后一点暗示,他们的成员类也不能static
,但是,没有规则禁止他们成为public
。
答案 1 :(得分:3)
您正在使用当前方法对MyEnum
进行子类化({}
语法创建一个匿名子类),它可以工作但看起来过于复杂。你拥有的东西等同于
public enum MyEnum {
first, second; // <-- convention would be FIRST, SECOND
public static class First { // <-- can be public.
}
public static class Second {
}
public Object getObject() {
if (this == first) {
return new First();
}
return new Second();
}
}