了解Java继承
考虑下面的Java代码:了解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
人们期望块1的输出为“因为a1的动态类型是B的事实,我注意到A和B中m1的函数签名不匹配(一个需要一个A类型的对象,另一个需要B的另一个作为它的参数)和A中的方法似乎得到优先权,但不能真正将它与我的输出链接,因为它似乎与th不一致块2的输出。
感谢您的时间
正如你注意到,B.m1(B)
不会覆盖A.m1(A)
,因为他们采取不同的参数(尝试添加@Override
注解,你会看到编译器抱怨)。所以它永远不能通过对A
的引用来调用。
但是,它可以通过参考B
来调用。
这两个方法签名与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在这方面关注的是,它不关心你做了什么对象,就是它是什么。
另外,按照您设置的方式,您是否打算为每个对象都有一个'toString'方法,然后将该对象传递给您的'p(Object o)'方法 – 2012-04-10 21:22:38
被调用的方法是在编译时设置的(在这种情况下是A.m1(A))。我知道你认为这是动态的吗?动态绑定是运行时绑定。嗯,是的,但它只对A.m1(A)的方法是动态的。因此,A的任何子类都可以提供一个替代实现,但其签名必须相同,否则就是重载方法,这与方法不同。
这也意味着呼叫中使用的参数没有考虑到动态绑定。方法名称和正式签名是在编译时设置的。改变类型,它不是相同的方法,不会被调用。
你可以做到这一点,以强制编译器看到的方法:
a1.m1((A)b1)
这告诉哪种方法你尝试调用编译器。
只需按照代码:
块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成为“B中的m1(B)”,只需将类A中的方法标记为虚拟,并在类B中覆盖相同。
的确,让它期待一个A实例,它就会起作用。 – MarioDS 2012-04-10 21:18:01