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

时间:2013-07-05 08:52:31

标签: java inner-classes access-modifiers anonymous-class jls

考虑这段代码:

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个成员类。然而...

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

什么? 为什么匿名类不能拥有publicprotectedprivate (以下简称those成员类,而{ {1}}成员字段和方法?困惑,我查看了JLS。由于Eclipse的说法,我首先考察了local classes

  

14.3。本地类声明

     

本地类是一个嵌套类(§8),它不是任何类的成员,并且具有名称(§6.2§6.7) 。
  如果本地类声明包含任何访问修饰符thosepublicprotected§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)   访问修饰符publicprotected§15.9.5)仅适用于直接封闭类或枚举声明(§6.6)中的成员类。

但是private是一个成员类,它位于一个直接封闭的类中,即匿名PrivateInnerClass,因此理论上它仍然可以有Cloneable个修饰符。我也查看了其他部分,但我仍然找不到相关条款。

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


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

  1. 匿名those 既不是会员类也不是本地类
  2. Cloneable是会员类,但不是本地班级
  3. 以下是我的测试代码:

    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成员字段和方法的原因。


3 个答案:

答案 0 :(得分:7)

你有:

  1. 顶级班级TopLevelClass未嵌套(因此被命名,非本地,不是匿名)
  2. 二级类,一个扩展Clonable且不属于任何类的成员的无名类:是匿名的(内部类,不是成员,属于本地范围但是不是“本地班级”)
  3. 第三级类PrivateInnerClass,匿名类的成员:是嵌套的,不是本地的,不是匿名的,是非静态的内部类
  4. 您正在使用(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中其他声明中的修饰符。否则,匿名类甚至不能拥有这些成员字段和方法。

    1. 在标识符

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

      为什么会这样?

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

      当声明

    2. 时,修饰符仅在法律宣布之前是合法的。

    3. ClassBody中修饰符的限制

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

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

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

    4. 所以8.1.1。限制两个地方的修饰语

    5. :)

答案 1 :(得分:3)

你错过了'包含'这个词。 PrivateInnerClass是您的匿名类的成员,它包含在其中,因此根据规则14.3,它本身不具有访问修饰符。

它的拥有成员可以拥有访问修饰符,但你还没有探索过。

Eclipse错误消息错误地将其描述为本地。

你也错过了'私人'即使它是合法的也不会添加任何东西这一点,因为内部类无论如何都是看不见的。

答案 2 :(得分:2)

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

  1. JLS中没有强有力的匿名类成员修饰符声明。即没有JLS的这一部分

  2. 但根据JVM规范匿名不是类成员:

  3. 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节)仅适用于   直接封闭类中的成员类

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