JLS 的哪一部分说匿名类不能有公共/受保护/私有成员类
Posted
技术标签:
【中文标题】JLS 的哪一部分说匿名类不能有公共/受保护/私有成员类【英文标题】:Which part of JLS said anonymous classes cannot have public/protected/private member classes 【发布时间】:2013-07-03 07:37:41 【问题描述】:考虑这段代码:
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
Eclipse 说:Illegal modifier for the local class PrivateInnerClass; only abstract or final is permitted
真的是本地类吗?
什么? 为什么匿名类不能有public
、protected
或private
(以下简称those
)成员类却可以有those
成员字段和方法? 很困惑,我调查了 JLS。由于 Eclipse 所说的,我首先查看了local classes:
14.3。本地类声明
本地类是一个嵌套类 (§8),它不是任何类的成员,并且有一个名称(§6.2、§6.7)。如果本地类声明包含任何访问修饰符
public
、protected
或private
(§6.6) 或修饰符static
(§8.1.1),则会出现编译时错误。
所以本地类不能有those
修饰符。但是PrivateInnerClass
是匿名Cloneable
的成员,所以它不是本地类,仍然可以有those
修饰符。
然后我查看了class modifiers:
8.1.1。类修饰符
访问修饰符
public
(§6.6) 仅适用于***类 (§7.6) 和成员类 (§8.5),不适用于本地类 (§14.3) 或匿名类 (@987654332 @)。 访问修饰符protected
和private
(§6.6) 仅适用于直接封闭类或枚举声明 (§8.5) 中的成员类。
但是PrivateInnerClass
是一个成员类,它在一个直接封闭的类中,匿名Cloneable
,所以理论上它仍然可以有those
修饰符。其他部分我也查了,还是没找到相关规定。
那么 Java 语言规范的哪一部分说匿名类的成员类不能有 those
修饰符?
额外说明 1: 一些答案是关于成员类和本地类的,所以我做了一个测试,可以得出结论(除非修饰符很重要):
-
匿名
Cloneable
既不是成员类也不是本地类。
PrivateInnerClass
是成员类,但不是本地类。
以下是我的测试代码:
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
补充说明 2: 查看普通类的声明(JLS §8.1):
普通类声明: ClassModifiersopt 类标识符 TypeParametersopt 超级opt 接口opt ClassBody据我了解,当Identifier
类是XXX类时,§8.1.1所说的是限制Identifier
的修饰符,而不是Identifier
的ClassBody
中其他声明中的修饰符。否则,匿名类甚至不能有those
成员字段和方法。
任何答案,尤其是不同意额外注释 2 的答案,必须指出为什么允许those
成员字段和方法。
额外说明 3:如果您认为 JLS 没有这部分,您仍然需要提供可靠的文件来解释为什么禁止使用 those
成员类和为什么允许those
成员字段和方法。
【问题讨论】:
随着时间的推移,您已经增加了答案的卷积。 @JoshDM 一半是为了展示我的“研究成果”。一半是告诉回答者“我发现了这些假证明,不要重复。” 【参考方案1】:你有:
-
***类
TopLevelClass
:没有嵌套(因此是命名的,不是本地的,不是匿名的)
二级类,无名类,扩展Clonable
,不是任何类的成员:是匿名的(内部类,不是成员,在本地范围内但不是'本地类')
三级类PrivateInnerClass
,匿名类的成员:是嵌套的,不是本地的,不是匿名的,是非静态的内部类
您在 (2) 中使用了修饰符 private
。您包含的 JLS 文字说明这是非法的:
8.1.1
访问修饰符 public(第 6.6 节)仅适用于***类(第 7.6 节)和成员类(第 8.5 节),不适用于本地类(第 14.3 节)或匿名类(§15.9.5)。 访问修饰符 protected 和 private (§6.6) 仅适用于直接封闭类或枚举声明 (§8.5) 中的成员类。
即您不能在匿名类内部(在其范围内)使用这些修饰符。
附注2的答案:
据我了解,当 Identifier 类是 XXX 类时,§8.1.1 所说的是限制 Identifier 的修饰符,而不是 Identifier 的 ClassBody 中其他声明中的修饰符。否则,匿名类甚至不能拥有那些成员字段和方法。
标识符前修饰符的限制
这在 8.1.1 中有详细说明。它显然适用。 所有修饰符都可以应用在成员类的标识符之前public
可以应用在***类标识符之前
在本地/匿名类(在本地范围内声明的类)的标识符之前不能应用任何修饰符
这是为什么?
因为成员类可以被其他类直接引用(通过***类的“成员链”),但本地/匿名类永远不能被外部引用。本地/匿名类声明隐藏在 Java 程序的任何其他部分本身无法访问的范围内。
当声明对其他类可访问时,修饰符仅在类声明之前是合法的。
ClassBody 中修饰符的限制
如果java程序的其他部分无法访问类标识符/声明,当然ClassBody也无法访问。
因此,只要修饰符在 Identifier 之前是非法的,修饰符在 ClassBody 中就没有可能的语义含义。
ClassBody 中是否允许使用修饰符的规则必须始终与是否允许在 Identifier 之前使用修饰符的规则相同。
所以 8.1.1。在两个地方都限制修饰符
:)
【讨论】:
请看我的编辑(附注 2)。有太多字不能评论。 1. 关于第二段有没有提到 JLS? 2. 为什么允许those
成员字段和方法? (例如我问题开头的代码)它们也无法访问,不是吗?
6.6: Qualified names are a means of access to members of packages and reference types. When the name of such a member is classified from its context (§6.5.1) as a qualified type name (denoting a member of a package or reference type, §6.5.5.2) or a qualified expression name (denoting a member of a reference type, §6.5.6.2), access control is applied.
6.6.1 A member (class, interface, field, or method) of a reference (class, interface, or array) type or a constructor of a class type is accessible only if the type is accessible and the member or constructor is declared to permit access
.
重新字段和方法:同意,它们也无法访问。似乎是编译器不一致。它们应该包含在 6.6 中。
@GlenBest Something you might want to know about【参考方案2】:
你错过了“包含”这个词。 PrivateInnerClass 是您的匿名类的成员,并且包含在其中,因此根据规则 14.3,它本身不能具有访问修饰符。
它可以对其自己的成员具有访问修饰符,但您还没有探索过。
Eclipse 错误消息错误地将其描述为本地。
您也错过了“private”即使合法也不会添加任何内容的观点,因为无论如何内部类都是不可见的。
【讨论】:
§14.3:“...如果本地类声明包含...”。本地班在哪里?匿名类和PrivateInnerClass
都不是本地类。【参考方案3】:
我的最终答案包括两个论点:
在 JLS 中没有对匿名类成员修饰符的严格限制声明。 IE。 JLS 中没有这样的部分。
但根据 JVM 规范匿名类不是类的成员:
JVM 7 规范:4.7.6 The InnerClasses Attribute 声明:
如果 C 不是类或接口的成员(也就是说,如果 C 是 ***类或接口 (JLS §7.6) 或本地类 (JLS §14.3) 或匿名类(JLS §15.9.5))...
所以,根据
8.5 成员类型声明
成员类是其声明直接包含在 另一个类或接口声明。
匿名类不是成员类。
所以,根据 8.1.1。类修饰符:
访问修饰符 protected 和 private (§6.6) 仅适用于 直接封闭类中的成员类
这些类不是成员类,所以它们不能提到修饰符。
【讨论】:
@johnchen902 好吧,这是我的最终答案。你可以同意也可以不同意。我已经提到,JLS 没有这样的部分。 @johnchen902 此类类的任何成员都不能有任何提及的修饰符 @johnchen902 我对 §8.1.1 有什么误解? @johnchen902 只是为了澄清我已经更新了我的答案。匿名类不是成员类。 让我们continue this discussion in chat以上是关于JLS 的哪一部分说匿名类不能有公共/受保护/私有成员类的主要内容,如果未能解决你的问题,请参考以下文章