2013-02-14 48 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