2013-02-14 23 views
2

我很困惑在Java中調度方法。爲什麼第一個方法「a.m1(b)」調用A類?Java調度 - 運行時類型

調用變量是a。它的運行時類型是B,不是嗎?

class A { 
    public void m1(A a){ 
     System.out.println("A-m1"); 
    } 
    public void m1(){ 
     System.out.println("A-m1"); 
    } 

} 
class B extends A { 
    public void m1(B b){ 
     System.out.println("B-m1"); 

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

    } 

} 
public class HelloWorld { 
    public static void main(String[] args) { 

    B b = new B(); 
    A a = new B(); 

     a.m1(b);//prints A-m1 
     a.m1();//prints B-m1 

    } 

} 

回答

7

超載分辨率是基於編譯時類型進行。 A類型的變量僅公開了方法m1()m1(A)。因爲你傳入一個參數,所以調用m1(A);或者更確切地說,適當的覆蓋其中的。除了m1(B)而不是覆蓋m1(A)。 (關於我的頭頂,我不知道overrides是否可以擴大參數簽名,但他們當然不能縮小它們。)

+1

非常感謝您的回答。但是,我不明白爲什麼不。例如,http://java-x.blogspot.de/2006/05/double-dispatch-in-java.html上的「ast1.collideWith(sp)」並未真正使用重載解析來理解,因爲雖然小行星也有collideWith(Spaceship),它與ExplodingAsteroid一致。你能解釋一下嗎? – Sammy 2013-02-14 18:11:34

+0

@Sammy你的情況與你鏈接的例子並不相似。 'collideWith(SpaceShip)'和'collideWith(GiantSpaceShip)'在編譯時很好解決,因爲當它們被調用時,'this'總是包含類的類型 - 當你遇到這種情況時,你故意使編譯時類型的'a'爲'A'。覆蓋方法也覆蓋了它們在超類中的相應重載,而不是重載不同的方法簽名。 (我不確定編譯器如何解決這種歧義的確切規則。) – millimoose 2013-02-14 18:16:21

+1

@Sammy或者,換句話說,有兩個步驟會發生:** 1。** * overload *是使用接收器的編譯時類型*和*參數。 ** 2。** *覆蓋*是使用接收器的運行時類型確定的。不同之處在步驟2.在你的情況下,'A.m1(A)'方法根本不會在'B'中覆蓋。在你鏈接的小行星/宇宙飛船的例子中,'Asteroid.collideWith(Spaceship)'被ExplodingAsteroid.collideWith(Spaceship)所覆蓋(簽名是相同的),所以如果運行時的接收器類型是ExplodingAsteroid,被調用。 – millimoose 2013-02-14 18:53:06