JLS的哪一部分表示匿名类不能拥有public/protected/private成员类

joh*_*902 11 java access-modifiers anonymous-class inner-classes jls

考虑一下这段代码:

public class TopLevelClass {
    Cloneable c = new Cloneable() {
        private int privateField;
        private void privateMethod() {};
    };
}
Run Code Online (Sandbox Code Playgroud)

有一个匿名类,它有一个private成员字段和一个private成员方法.它已成功编译.

然后考虑这个:

public class TopLevelClass {
    Cloneable c = new Cloneable() {
        private class PrivateInnerClass {}
    };
}
Run Code Online (Sandbox Code Playgroud)

有一个匿名类,它有一个private成员类.然而...

  • javac说: error: modifier private not allowed here
  • 日食说:Illegal modifier for the local class PrivateInnerClass; only abstract or final is permitted 真的是本地课吗?

什么?为什么匿名类不能有public,protectedprivate(以下简称为those)成员类而它们可具有those构件的字段和方法?困惑,我看着JLS.由于Eclipse所说的,我首先研究了本地课程:

14.3.本地类声明

局部类是一个嵌套类(§8)不属于任何类的成员,并且具有名称(§6.2,§6.7).
这是一个编译时错误,如果一个本地类声明包含任何访问修饰符public,protectedprivate(6.6节),或改性剂static(§8.1.1).

所以本地类不能有those修饰符.不过PrivateInnerClass 匿名的成员Cloneable,所以它不是本地类,并仍然能够有those修饰语.

然后我查看了类修饰符:

8.1.1.类修饰符

访问修饰符public(第6.6节)仅适用于顶级类(第7.6节)和成员类(第8.5节),不适用于本地类(第14.3节)或匿名类(第15.9.5节).
访问修饰符protectedprivate(§6.6)仅适用于直接封闭类或枚举声明(第8.5节)中的成员类.

但是它PrivateInnerClass是一个成员类,并且它在一个直接封闭的类中,匿名Cloneable,所以它those在理论上仍然可以有修饰符.我也查看了其他部分,但我仍然找不到相关条款.

那么Java语言规范的哪一部分说匿名类的成员类不能有those修饰符?


额外注1:有些回答是关于成员类和本地类的,所以我做了一个测试,可以得出结论(除非修饰符很重要):

  1. 匿名Cloneable既不是成员类,也不是局部类.
  2. 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
    }
}
Run Code Online (Sandbox Code Playgroud)

额外注释2: 审查正常类的声明(JLS§8.1):

NormalClassDeclaration:
    ClassModifiersopt class Identifier TypeParametersopt
                                               Superopt Interfacesopt ClassBody

在我的理解中,当Identifier类是XXX级,什么§8.1.1说是限制的修改Identifier,而不是在其他声明的修饰符ClassBodyIdentifier.否则,匿名类甚至不能拥有those成员字段和方法.

任何答案,特别是不同意额外注释2的答案,必须指出为什么those允许成员字段和方法.


额外注释3:如果您认为没有JLS的这一部分,您仍需要提供可靠的文档来解释those禁止成员类的原因those以及允许成员字段和方法的原因.


Gle*_*est 7

你有:

  1. 顶级类TopLevelClass:不嵌套(因此命名,不是本地,不是匿名)
  2. 二级类,一个扩展的无名类,并且不是Clonable任何类的成员:是匿名的(内部类,不是成员,在本地范围内,但不是"本地类")
  3. 三级类PrivateInnerClass,匿名类的成员:是嵌套的,不是本地的,不是匿名的,是非静态的内部类

您正在使用private(2)中的修饰符.您收录的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中其他声明中的修饰符.否则,匿名类甚至不能拥有那些成员字段和方法.

  1. 在标识符之前限制修饰符

    • 这在8.1.1中有详细说明.它显然适用.
    • 所有修饰符都可以在成员类的标识符之前应用
    • public 可以在顶级类标识符之前应用
    • 没有修饰可以本地/匿名类的标识符之前应用(在本地范围内声明的类)

    为什么是这样?

    因为成员类可以由其他类直接引用(通过顶级类中的"成员链"),但是本地/匿名类永远不能在外部引用.本地/匿名类声明隐藏在本身不能被java程序的任何其他部分访问的作用域中.

    当声明可供其他类访问时,修饰符在类声明之前是合法的.

  2. ClassBody中修饰符的限制

    如果Java程序的其他部分无法访问类标识符/声明,当然也无法访问ClassBody.

    因此,只要修饰符在标识符之前是非法的,修饰符就可能在ClassBody中没有可能的语义含义.

    在ClassBody 中是否允许修饰符的规则必须始终与在标识符之前是否允许修饰符的规则相同.

  3. 所以8.1.1.限制两个地方的修饰符

:)

  • @GlenBest [你想知道的事情](http://meta.stackexchange.com/q/188588/155556) (5认同)

And*_*niy 2

我的最终答案包括两个论文:

\n\n
    \n
  1. JLS 中没有对匿名类成员修饰符的严格限制声明。即JLS 没有这样的部分

  2. \n
  3. 但根据 JVM 规范,匿名不是类的成员:

  4. \n
\n\n

JVM 7 规范:4.7.6 InnerClasses 属性指出:

\n\n
\n

如果 C 不是类或接口的成员(即,如果 C 是顶级类或接口 (JLS \xc2\xa77.6) 或本地类 (JLS \xc2\xa714.3) \n 或匿名类 (JLS \xc2\xa715.9.5))...

\n
\n\n

所以,根据

\n\n

8.5 成员类型声明

\n\n
\n

成员类是其声明直接包含在另一个类或接口声明中的类。

\n
\n\n

匿名不是成员类

\n\n

因此,根据8.1.1。类修饰符

\n\n
\n

访问修饰符 protected 和 private (\xc2\xa76.6) 仅适用于\n 直接封闭类中的成员类

\n
\n\n

这个类不是成员类,所以它们不能有提到的修饰符

\n