【问题标题】:Outer vs. Super class外部与超级类
【发布时间】:2011-08-17 13:26:12
【问题描述】:

super 的优先级是否高于outer class?

假设我们有三个类:

  1. A 类
  2. B 类
  3. ClassB 中扩展 ClassA 的匿名类

ClassA.java:

public class ClassA {
    protected String var = "A Var";

    public void foo() {
        System.out.println("A foo()");
    }
}

ClassB.java:

public class ClassB {
    private String var = "B Var";

    public void test() {

        new ClassA() {
            public void test() {
                foo();
                System.out.println(var);
            }
        }.test();
    }

    public void foo() {
        System.out.println("B foo()");
    }
}

当我打电话给new ClassB().test() 时,我得到以下输出(这几乎是预期的):

A foo()
A Var

问题:是否定义了内部类首先从超类获取(方法和成员)然后从外部类获取的地方,还是依赖于 JVM 编译器实现?我查看了 JLS(§15.12.3),但找不到任何参考,也许它在那里被指出,但我误解了一些条款?

【问题讨论】:

  • 我尝试遵循 JLS 中的逻辑,但还没有喝咖啡 ;-) 根据经验我会说:我漂亮确定这是明确指定且依赖于实现。 如果它是依赖于实现的,那么它将取决于编译器而不是JVM,因为该决定是在编译时完成的。
  • @Joachim - 我写错了 JVM,感谢您指出这一点。

标签: java inheritance inner-classes


【解决方案1】:

6.3.1 Shadowing Declarations:

一个名为 n 的方法的声明 d 隐藏在封闭范围内的任何其他名为 n 的方法的声明d 出现在整个 d 范围内的位置。

可能被解释为“foo 的声明(继承自 ClassA)隐藏了任何其他名为 foo 且位于封闭范围内的方法的声明 (ClassB ) 在foo 出现的点,在整个foo 的范围内。”

同样相关 - 15.12.1 部分:

15.12.1 编译时步骤 1:确定要搜索的类或接口

在编译时处理方法调用的第一步是确定要调用的方法的名称以及要检查该名称的方法定义的类或接口。有几种情况需要考虑,具体取决于左括号前面的形式,如下所示:

  • 如果表单是MethodName,那么有三个子情况:
    • 如果是简单的名字,即只是一个Identifier,那么方法的名字就是Identifier。如果标识符出现在具有该名称的可见方法声明的范围(第 6.3 节)内,则必须存在该方法是其成员的封闭类型声明。让 T 成为最里面的这种类型声明。 要搜索的类或接口是 T
    • 如果它是 TypeName.Identifier 形式的限定名称,则 [...]
    • 在所有其他情况下,限定名称的格式为 FieldName.Identifier;然后 [...]

【讨论】:

  • @aioobe - 谢谢,但我仍然不清楚,因为 ClassB 方法和成员在匿名类的范围内。我可能错过了这一点,但在您发布的内容中,我仍然没有看到超类(在我的示例中为 ClassA)的优先级。
  • 嗯..真的。我会看看能不能找到更具体的东西。
  • @aioobe - 再次感谢,我希望你不要以为我会派你去工作,我只是一遍又一遍地看它,无法弄清楚.. .
  • 哦,不。我喜欢浏览 JLS。我每次都能学到新东西 :-)
  • 还有 §6.5.6 表达式名称的含义 (java.sun.com/docs/books/jls/third_edition/html/…)
【解决方案2】:

我想你总是会收到"A var"

这是因为您的test() 方法实现是在A 的匿名子类上定义的。我认为您不能在 test() 方法中访问 B.var 实例变量,除非您使用 ClassB.this.var 显式引用外部类。

【讨论】:

  • @The Captain - 如果我从 ClassA 中删除 var,我确实会从 ClassB 中获得 var。我正在尝试了解并确认如果我不删除它会发生什么。
  • 当然...我认为这是因为ClassA.var 在您的示例中影响了ClassB.var。因此,虽然这两个定义都存在,但从 A.test() 引用 var 将始终获得 ClassA 版本。
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 2023-01-24
  • 2018-05-22
  • 2016-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-30
相关资源
最近更新 更多