2011-05-03 95 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