给出以下Java代码:
class mainul {
public static void main(String[] args) {
/*block 1*/
B b1 = new B();
A a1 = b1;
a1.m1(b1);
/*block 2*/
B b2 = new B();
B a2 = b2;
b2.m1(a2);
}
}
class A {
public static void p(Object o) {
System.out.println(o.toString());
}
public void m1(A a) {
p("m1(A) in A");
}
}
class B extends A {
public void m1(B b) {
p("m1(B) in B");
}
}
有人可以解释为什么这个程序的输出是
m1(A) in A
m1(B) in B
由于a1的动态类型为B,我们可以预期块1的输出为“m中的m1(B)”。我注意到A和B中m1的函数签名不匹配(一个期望A类型的对象和B的另一个对象作为其参数)并且A中的方法似乎获得优先级但不能真正将其链接到我的输出,因为它似乎与block2的输出不一致。
感谢您的时间
答案 0 :(得分:7)
正如您所注意到的,B.m1(B)
不会覆盖A.m1(A)
,因为它们采用不同的参数(尝试添加@Override
注释,您会看到编译器抱怨)。因此,永远不能通过引用A
来调用它。
但是,可以通过引用B
来调用它。
答案 1 :(得分:1)
被调用的方法在编译时设置(在本例中为A.m1(A))。我知道你认为这是动态的吗?动态绑定是运行时绑定。好吧是的,但它只对A.m1(A)上的方法有动态。因此,A的任何子类都可以提供替代实现,但其签名必须相同,否则这是一个重载方法,这是不同的方法。
这也意味着动态绑定不会考虑呼叫中使用的参数。方法名称和正式签名在编译时设置。更改类型,它不是相同的方法,不会被调用。
您可以这样做以强制编译器查看方法:
a1.m1( (A)b1 )
告诉编译器你试图调用哪种方法。
答案 2 :(得分:1)
只需按照代码:
第1块
B b1 = new B(); //- variable b1 (type is B) points to instance of B()
A a1 = b1; //- variable a1 (type is A) points to instance of B() .. same as b1 is
// pointing to.
a1.m1(b1); // Call Method m1 on a1 (i.e. of class A ) ..IMP catch > as a1 holds
// object of b1, if there is method in Class A which is overriden in B,
// call that overriden method. But here method m1() is not overriden
// by B it will call method of class A.
第2块
B b2 = new B(); // variable b2 (type B) points to instance of B()
B a2 = b2; // variable a2 (type B) points to same instance as b2 is pointing to.
b2.m1(a2); // call method m1 of b2 (of class B). There is only one method m1 in b2
// and b2 holds object of B, it must call method of class B
此外,如果您希望块1中的“m1(B)在B中”,只需将A类中的方法标记为虚拟,并在B类中覆盖相同的方法。
答案 3 :(得分:0)
Oli说,这两种方法的签名是不同的。
当你在这里打电话给他们时:
B b1 = new B();
A a1 = b1;
a1.m1(b1);
/*block 2*/
B b2 = new B();
B a2 = b2;
b2.m1(a2);
首先传递一个类型为A的对象,然后传递一个类型为B的对象。这就是Java在这个上下文中所关心的,它并不关心你创建对象的内容,只是它是什么。