有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java 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成员类,而它们可以有those成员字段和方法我困惑地看着JLS。由于Eclipse所述,我首先研究了local classes

14.3. Local Class Declarations

A local class is a nested class (§8) that is not a member of any class and that has a name (§6.2, §6.7).
It is a compile-time error if a local class declaration contains any of the access modifiers public, protected, or private (§6.6), or the modifier static (§8.1.1).

所以本地类不能有those修饰符。但是PrivateInnerClass是匿名Cloneable的成员,因此它不是本地类,并且仍然可以有those修饰符

然后我研究了class modifiers

8.1.1. Class Modifiers

The access modifier public (§6.6) pertains only to top level classes (§7.6) and to member classes (§8.5), not to local classes (§14.3) or anonymous classes (§15.9.5).
The access modifiers protected and private (§6.6) pertain only to member classes within a directly enclosing class or enum declaration (§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
    }
}

额外说明2: 查看普通类(JLS §8.1)的声明:

NormalClassDeclaration:
    ClassModifiersopt class Identifier TypeParametersopt
                                               Superopt Interfacesopt ClassBody

在我的理解中,当Identifier类是XXX类时,§8.1.1所述的是限制Identifier的修饰符,而不是ClassBody中其他声明中的修饰符。否则,匿名类甚至不能有those成员字段和方法

任何答案,尤其是与额外注释2不一致的答案,必须指出为什么允许使用those成员字段和方法


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



共 (3) 个答案

  1. # 1 楼答案

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

    1. JLS中没有对匿名类成员修饰符的严格限制声明。也就是说,JLS中没有这样的部分

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

    JVM 7规范:声明:

    If C is not a member of a class or an interface (that is, if C is a top-level class or interface (JLS §7.6) or a local class (JLS §14.3) or an anonymous class (JLS §15.9.5))...

    所以,根据

    8.5成员类型声明

    A member class is a class whose declaration is directly enclosed in another class or interface declaration.

    匿名不是成员类

    因此,根据8.1.1。类修饰符

    The access modifiers protected and private (§6.6) pertain only to member classes within a directly enclosing class

    这些类不是成员类,所以它们不可能提到修饰符

  2. # 2 楼答案

    你有:

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

    您正在使用(2)中的修饰符private。您随附的JLS文本说明这是非法的:

    8.1.1

    The access modifier public (§6.6) pertains only to top level classes (§7.6) and to member classes (§8.5), not to local classes (§14.3) or anonymous classes (§15.9.5). The access modifiers protected and private (§6.6) pertain only to member classes within a directly enclosing class or enum declaration (§8.5).

    也就是说,你不能在匿名类中使用这些修饰符


    对补充说明2的答复:

    In my understanding, when the Identifier class is an XXX class, what §8.1.1 stated is restricting the modifier of Identifier, not the modifiers in other declarations in ClassBody of Identifier. Otherwise, anonymous classes even cannot have those member fields and methods.

    1. 标识符前修饰语的限制

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

      这是为什么

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

      修饰符在类声明之前是合法的,而其他类可以访问该声明

    2. 类体内修饰语的限制

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

      因此,每当一个修饰语在标识符之前是非法的,修饰语在类主体中就可能没有可能的语义

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

    3. 所以8.1.1。限制两个位置的修饰符

    :)

  3. # 3 楼答案

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

    它可以为自己的成员设置访问修饰符,但你还没有研究过

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

    你还忽略了一点,即“private”即使是合法的,也不会添加任何内容,因为内部类无论如何都是不可见的