git reset --hard HEAD
输出
public class Tester {
public static void main(String[] args) {
A a2 = new B();
a2.dosomething1(new B());
a2.dosomething2(new B());
}
}
class A {
public void dosomething1(A a){
System.out.println("Inside a dosomething1");
}
public void dosomething2(A a){
System.out.println("Inside a dosomething2");
}
}
class B extends A {
public void dosomething1(A a){
System.out.println("Inside b dosomething1");
}
public void dosomething2(B b){
System.out.println("Inside b dosomething2");
}
}
输出中的第一行显然是由于方法覆盖。 但是第二线背后的原因是什么?为什么java没有调用B中定义的方法,因为在运行时它知道a2是B的对象。
答案 0 :(得分:6)
您需要回答的问题是:B.dosomething2(B b)
可以完全取代A.dosomething2(A a)
吗?或者更具体地说:A.dosomething2(A a)
接受的每个参数值是否也可以传递给B.dosomething2(B b)
?
答案很简单:不。
B obj_B= new B();
A obj_A= new A();
obj_B.doSomething2(obj_A);
上面的示例应明确原因:obj_A
不是B
的实例,因此无法作为参数传递给B.dosomething2(B b)
。这意味着这两种方法虽然共享相同的名称但不共享相同的签名,这反过来意味着我们重载该方法而不是覆盖它。
事实上,碰巧用适合两者的东西调用它是无关紧要的,因为选择哪个重载方法在Java编译时调用,基于变量{ {1}}的类型(a2
)而不是它指向的对象的运行时类(A
)。
这种错误很容易发生,特别是如果你改变你的方法并重命名它们。为了避免在意图重写时意外重载,请确保在打算覆盖某些内容时始终使用B
注释,这样编译器会抱怨。
@Override
这个注释在技术上是可选的,但它非常有用,在实践中人们将其视为强制性的。
答案 1 :(得分:2)
方法重写
为什么java没有调用B中定义的方法,因为在运行时它知道a2 是B的对象。
因为class B extends A {
@Override //this will compile fine
public void dosomething1(A a){
System.out.println("Inside b dosomething1");
}
@Override //this will fail compilation
public void dosomething2(B b){
System.out.println("Inside b dosomething2");
}
}
中的dosomething2
和A
中的dosomething2
具有不同的签名。
您没有在B
覆盖dosomething2
。关于动态调度,B
中的dosomething2
是一种新方法。