2011-05-03 66 views
14

超级比外部类别具有更高的优先级吗?外部与超级类别

考虑,我们有三类:

  1. ClassA的
  2. ClassB的
  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),但找不到任何参考,可能是在那里指出的,但我误解了一些术语?

+3

我试图按照JLS中的逻辑,但没有我的咖啡;-)从经验我会说:我**漂亮**确定这是很好的指定和**不* *依赖于实现。 *如果*它是实现相关的,那么它将取决于编译器,而不取决于JVM,因为该决定是在编译时完成的。 – 2011-05-03 09:11:29

+0

@Joachim - 我错误地写了JVM,谢谢指出。 – MByD 2011-05-03 09:17:27

回答

5

参见6.3.1 Shadowing Declarations

的声明命名Ñ阴影的命名Ñ是在一个封闭的范围点在哪里d任何其他方法的声明方法的d发生在整个d的范围内。

哪个可以被解释为“foo(来自ClassA继承)的声明阴影命名foo任何其他方法,这些方法在其中foo发生点的封闭范围(ClassB)的声明,在整个foo的范围。“

另外相关 - 部分15.12.1

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

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

  • 如果表单方法名,然后有三个子情况:
    • 如果它是一个简单的名称,即只是一个标识符,那么方法的名称就是标识符。如果标识符出现在具有该名称的可见方法声明的范围(第6.3节)中,则必须有该方法所属的包含类型声明。设T是最内层的类型声明。 要搜索的类别或接口是T
    • 如果它是格式TypeName.Identifier的合格名称,则[
    • 在其他所有情况下,限定名称的格式为FieldName.Identifier;然后[...]
+0

@aioobe - 谢谢,但它仍然不清楚,因为ClassB方法和成员都在匿名类的范围内。我可能会错过这一点,但我仍然没有看到你发布的超级类(在我的例子中是ClassA)。 – MByD 2011-05-03 09:34:32

+0

嗯..真的。我会看看我能否找到更具体的东西。 – aioobe 2011-05-03 09:35:46

+0

@aioobe - 再次感谢,我希望你不要以为我会派你去为我工作,我只是一遍又一遍地看着它,无法想象它...... – MByD 2011-05-03 09:36:54

1

我认为你总是会得到"A var"

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

+0

@队长 - 如果我从ClassA中移除'var',我确实从ClassB中获得var。我试图了解并确认如果我不删除它会发生什么情况。 – MByD 2011-05-03 09:29:53

+0

当然...我认为这是因为'ClassA'.'var'在你的例子中是阴影'ClassB'.'var'。因此,虽然两个定义都存在,但引用'A.test()'中的'var'将始终获得'ClassA'版本。 – 2011-05-03 09:53:36