2013-06-12 52 views
3
public class A{ 
    public static int x = 1; 
    public int m(A a, B b){ 
     return a.m(b, b) + x; 
    } 
} 

public class B extends A { 
    public int m(A a1, B a2){ 
     if(a1 == a2) 
      return x; 
     return super.m(a1,a2); 
    } 
} 

這是一個來自我正在考試的科目考試的問題。覆蓋 - 參數差異

public class Main{ 
    public static void main(String[] args){ 
     B b1 = new B(){int m(A a, A b){ return 10; }}; 
     System.out.println(b1.m(b1, b1)); 
    } 
} 

問題是,下面的輸出是什麼。我的答案是正確的,但我沒有完全明白爲什麼。

由於B對象的內部類是(A,A)。我是否認爲它不能覆蓋超級方法m,因爲它是(A,B)?如果兩個方法的參數交換了,它能重寫嗎?

既然它既不能覆蓋也不能重載,它什麼也不做,只是使用B類中的方法m?

對象的內部類是否僅爲其自身工作?它是否像一個匿名課?

對所有問題表示歉意。

在此先感謝。

編輯:

從我的理解,到目前爲止,其因爲靜態類型設置爲B,那麼B型是無法看到匿名類。如果這是公開的,它可以被看到,但它仍然不會被使用。

這使我對另一個問題感到困惑。

public class A{ 
    public static int x = 1; 
    public int m(A a, B b){ 
     return a.m(b, b) + x; 
    } 
} 

public class Main{ 
public static void main(String[] args){ 
    A a1=new A(); 
    A a2=new A(){ 
    int m(A a,B b){ 
    return 10; 
    }}; 
    B b1=new B(); 
    System.out.println(a1.m(a2,b1)); 
} 
} 

當下面被調用時,輸出爲11 當a1.m被調用時,它經過A2及B1的。

在A類中,當調用a.m(b,b)時。它調用動態類型。這是因爲它一旦解析就更改爲動態類型?那麼現在它能夠使用匿名類嗎?

+0

回答如下,請告訴我,如果事情是模糊的。這是頗有些運動在這裏;) – fge

回答

1

這裏有幾點:

  • 在匿名內部類中的方法是不公開的,所以不能覆蓋的公共方法。如果您必須重寫非抽象方法,請始終使用@Override
  • b1的(靜態)類型爲B,因此以匿名類型聲明的額外方法不可用。雖然你可以做這樣的事情:

    B b1 = null; 
    System.out.println(new B(){int m(B a, B b){ return 10; }.m(b1, b1)); 
    

或者

final B b1 = null; 
    new B() { 
     { 
      System.out.println(this.m(b1, b1)); 
     } 
     int m(B a, B b) { return 10; } 
    }; 
  • 的語言,最具體的參數選擇倍率(如果存在的話),而不是最不具體。在前面的例子中已經修正。例如System.err.println("donkey".toCharArray());不會撥打println(Object)
  • 覆蓋方法可以放鬆返回類型,「協變返回值類型」(自1.5)。超類型的泛型參數類型(例如Comparable)中的參數不完全相同。
+0

謝謝,這幫助了我。但提出了另一個問題。我在原帖的末尾編輯過。 – user2469515

+0

@ user2469515重載是在編譯時靜態地在變量的靜態類型上完成的。當方法執行時,變量正好指向的類型將被覆蓋。有些語言允許在多種類型(多派遣,或者只是雙派遣)上進行動態分派,但也存在一些問題。 –

+0

感謝您的幫助 – user2469515

6

讓我們走過的JVM:

B b1 = new B(){ int m(A a,A b) { return 10; } }; 

這具有A類型的兩個參數方法m()的匿名過載造成的B一個實例。但是,這是一個不同m()方法比類B(或A)定義,因爲他們簽名A, A VS A, B)不同。

然後:

System.out.println(b1.m(b1, b1)); 

這要求b1m()方法與B類型的兩個參數。

現在JVM查找什麼m()是:

  • 沒有方法有B類型的兩個參數m();
  • B類,它找到一個匹配:由名稱m()它的第一個參數是一個A(因爲B繼承A),並且是B類型的第二個參數的方法;
  • b1匿名重載是完全忽略這裏!(參見https://gist.github.com/fge/5762353
  • 方法查找結束。

因此調用B類的m()方法。而在這個方法中,我們有:

if (a1 == a2) // TRUE! 
    return x; 

由於條件爲真(該方法被調用的兩個參數是完全相同的對象引用),必須返回的x價值;

public static int x = 1; 

由於這是類A(其中B類不隱藏)它是由實例方法同樣可訪問的,從任何實例的靜態構件:和xA類,這類Bextends定義AB;因此,該程序的返回代碼和輸出爲1.

+0

它不是在匿名內部類中定義的方法尋找,因爲(靜態)類型b1'的''是B'。 –

+0

否。嘗試使用'm()'的匿名重載的示例代碼,它有兩個類型爲'B'的參數而不是'A':返回的值爲10!因爲'B,B'更具體,'A,B';但在這裏,超載是'A,A',它是_less_特定的。 – fge

+0

如果是這樣,我認爲在javac中有一個錯誤。 (我沒有我自己的機器上安裝了Java。) –

4

我正確認爲它不能覆蓋超級方法m,因爲它是(A,B)?

是的,你是正確的:這將創建一個超載,不是重寫基類中的方法的

如果兩個方法的參數交換,它能重寫嗎?

否:要覆蓋,方法簽名必須完全匹配。

既然它既不能覆蓋也不能重載,它什麼都不做,只是使用B類中的方法m?

不完全是:(A, B)過載恰好比(A, A)過載更具體。

該對象的內部類是否僅適用於自己?它是否像一個匿名課?

你將能夠在內部類中調用該方法,如果你通過了一對A s。