考虑这段代码:
public class TopLevelClass {
Cloneable c = new Cloneable() {
private int privateField;
private void privateMethod() {};
};
}
有一个匿名类,其中包含private
成员字段和private
成员方法。它已成功编译。
然后考虑这个:
public class TopLevelClass {
Cloneable c = new Cloneable() {
private class PrivateInnerClass {}
};
}
有一个匿名类,它有private
个成员类。然而...
error: modifier private not allowed here
Illegal modifier for the local class PrivateInnerClass; only abstract or final is permitted
真正的本地课程? 什么? 为什么匿名类不能拥有public
,protected
或private
(以下简称those
)成员类,而{ {1}}成员字段和方法?困惑,我查看了JLS。由于Eclipse的说法,我首先考察了local classes:
14.3。本地类声明
本地类是一个嵌套类(§8),它不是任何类的成员,并且具有名称(§6.2,§6.7) 。
如果本地类声明包含任何访问修饰符those
,public
或protected
(§6.6)或修饰符,则为编译时错误private
(§8.1.1)。
因此本地课程不能拥有static
修饰符。但those
是匿名PrivateInnerClass
的成员,因此它不是本地类,仍然可以拥有Cloneable
修饰符。
然后我调查了class modifiers:
8.1.1。类修饰符
访问修饰符
those
(§6.6)仅适用于顶级类(§7.6)和成员类(§8.5),而不属于本地类({{ 3}})或匿名课程(§14.3) 访问修饰符public
和protected
(§15.9.5)仅适用于直接封闭类或枚举声明(§6.6)中的成员类。
但是private
是一个成员类,它位于一个直接封闭的类中,即匿名PrivateInnerClass
,因此理论上它仍然可以有Cloneable
个修饰符。我也查看了其他部分,但我仍然找不到相关条款。
那么Java语言规范的哪一部分说匿名类的成员类不能有those
修饰符?
额外注1:有些回答是关于成员类和本地类的,所以我做了一个测试,可以得出结论(除非修饰符很重要):
those
既不是会员类也不是本地类。Cloneable
是会员类,但不是本地班级。以下是我的测试代码:
PrivateInnerClass
额外注2: 查看普通类的声明(§8.5):
NormalClassDeclaration: ClassModifiersopt class Identifier TypeParametersopt Superopt Interfacesopt ClassBody
根据我的理解,当public class TopLevelClass {
Cloneable c = new Cloneable() {
class PrivateInnerClass {}
};
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c1 = Class.forName("TopLevelClass$1");
Class<?> c2 = Class.forName("TopLevelClass$1$PrivateInnerClass");
System.out.println(c1.isMemberClass()); // false
System.out.println(c1.isLocalClass()); // false
System.out.println(c2.isMemberClass()); // true
System.out.println(c2.isLocalClass()); // false
}
}
班级是XXX班级时,JLS §8.1所述内容限制了Identifier
的修饰符,而不是Identifier
中其他声明中的修饰符ClassBody
。否则,匿名类甚至不能拥有Identifier
成员字段和方法。
任何答案,特别是不同意额外注释2的答案,必须指出为什么允许those
成员字段和方法。
额外注3:如果您认为JLS没有这部分,您仍需要提供可靠的文档来解释为什么those
成员类是禁止以及允许those
成员字段和方法的原因。
答案 0 :(得分:7)
你有:
TopLevelClass
:未嵌套(因此被命名,非本地,不是匿名) Clonable
且不属于任何类的成员的无名类:是匿名的(内部类,不是成员,属于本地范围但是不是“本地班级”) PrivateInnerClass
,匿名类的成员:是嵌套的,不是本地的,不是匿名的,是非静态的内部类 强> 您正在使用(2)中的修饰符private
。你收录的JLS文字说明这是非法的:
8.1.1
访问修饰符public(第6.6节)仅适用于顶级类(第7.6节)和成员类(第8.5节),不适用于本地类(第14.3节)或匿名课程(§15.9.5)。 受保护的访问修饰符和私有(第6.6节)仅在直接封闭的类或枚举声明(第8.5节)中将仅限于成员类。
即。你可以在匿名类的内部(在范围内)不使用这些修饰符。
回答额外注2:
根据我的理解,当Identifier类是一个XXX类时,所述的§8.1.1限制了Identifier的修饰符,而不是Identifier ClassBody中其他声明中的修饰符。否则,匿名类甚至不能拥有这些成员字段和方法。
在标识符
之前限制修饰符public
可以在顶级类标识符为什么会这样?
因为成员类可以由其他类直接引用(通过顶级类中的“成员链”),但本地/匿名类永远不能在外部引用。本地/匿名类声明隐藏在本身不能被java程序的任何其他部分访问的作用域中。
当声明
ClassBody中修饰符的限制
如果java程序的其他部分无法访问类标识符/声明,当然也无法访问ClassBody。
因此,只要修饰符在标识符之前是非法的,修饰符就不会在ClassBody中具有可能的语义含义。
在ClassBody 中是否允许使用修饰符的规则必须始终与之前是否允许修饰符的规则相同。
所以8.1.1。限制两个地方的修饰语
:)
答案 1 :(得分:3)
你错过了'包含'这个词。 PrivateInnerClass是您的匿名类的成员,它包含在其中,因此根据规则14.3,它本身不具有访问修饰符。
它的拥有成员可以拥有访问修饰符,但你还没有探索过。
Eclipse错误消息错误地将其描述为本地。
你也错过了'私人'即使它是合法的也不会添加任何东西这一点,因为内部类无论如何都是看不见的。
答案 2 :(得分:2)
我的最终答案包括两个论点:
JLS中没有强有力的匿名类成员修饰符声明。即没有JLS的这一部分。
但根据JVM规范匿名类不是类成员:
JVM 7规范: 4.7.6 The InnerClasses Attribute 状态:
如果C不是类或接口的成员(即,如果C是a 顶级类或接口(JLS§7.6)或本地类(JLS§14.3) 或匿名课程(JLS§15.9.5))......
所以,根据
8.5会员类型声明
成员类是一个直接包含其声明的类 另一个类或接口声明。
匿名类不是成员类。
所以,根据 8.1.1。类修饰符:
受保护的访问修饰符和私有(第6.6节)仅适用于 直接封闭类中的成员类
这个类不是成员类,所以他们不能提到修饰符。