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


考虑这段代码:

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  真的是本地班吗?

什么? 为什么匿名类不能拥有 publicprotected 要么 private(以下简称 those 他们可以拥有的成员课程 those 会员字段和方法? 困惑,我看着JLS。因为Eclipse所说的,我调查了一下 当地的课程 第一:

14.3。本地类声明

一个 当地班级 是一个嵌套类(§8)这不是任何类的成员,并且具有名称(6.2节§6.7)。
如果本地类声明包含任何访问修饰符,则为编译时错误 publicprotected, 要么 private (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)。
  访问修饰符 protected 和 private (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
    }
}

额外注2: 检查正常班级的声明(JLS§8.1):

NormalClassDeclaration:
    ClassModifiers选择 class Identifier TypeParameters选择
                                               超选择 接口选择 ClassBody

在我的理解中,当 Identifier class是一个XXX类,什么 §8.1.1 陈述是限制的修饰语 Identifier,而不是其他声明中的修饰语 ClassBodyIdentifier。否则,匿名类甚至不能拥有 those 成员字段和方法。

任何答案,尤其是不同意Extra Note 2的答案,必须指出原因 those 允许使用成员字段和方法。


额外注3: 如果您认为JLS没有这样的部分, 你还需要提供一份可靠的文件来解释原因 those 成员类是禁止的,为什么 those 允许使用成员字段和方法。



6355
2017-07-05 08:52


起源

随着时间的推移,你已经增加了答案的卷积。 - JoshDM
@JoshDM其中一半是展示我的“研究工作”。其中一半是告诉回答者“我发现了这些假证据,不要重复它。” - johnchen902


答案:


你有:

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

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


7
2017-07-07 12:37



纠正。谢谢! - Glen Best
请参阅我的编辑(额外注释2)。评论中有太多的词语。 - johnchen902
谢谢。更新了我的A. :) - Glen Best
1。 有关第二段的任何JLS参考? 2。 为什么 those 允许成员字段和方法? (比如我问题开头的代码)他们也无法访问,不是吗? - johnchen902
@GlenBest 你有事吗 威力 想知道 - Neal


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

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

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

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


3
2017-07-06 02:16



§14.3:“...如果 当地的一个班级 声明包含......“。本地班级在哪里?既不是匿名班级,也不是 PrivateInnerClass 是一个本地班级。 - johnchen902


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

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

  2. 但根据JVM规范 匿名 类  班级成员:

JVM 7规范: 4.7.6 InnerClasses属性 状态:

如果C不是类或接口的成员(即,如果C是a   顶级类或接口(JLS§7.6)或本地类(JLS§14.3)   或匿名课程(JLS§15.9.5))...

所以,根据

8.5会员类型声明

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

匿名 类 不是会员类

所以,根据 8.1.1。类修饰符

访问修饰符protected和private(§6.6)仅适用于   直接封闭类中的成员类

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


2
2017-07-05 10:57



@ johnchen902嗯,这是我的最终答案。你可以同意与否。我已经提到过,JLS没有这样的部分。 - Andremoniy
@ johnchen902这类的任何成员都不能有任何提到的修饰符 - Andremoniy
@ johnchen902我对§8.1.1的误解是什么? - Andremoniy
@ johnchen902只是为了澄清我已经更新了我的答案。匿名类不是成员类。 - Andremoniy
让我们 在聊天中继续讨论 - Andremoniy