我有一个简单的代码,我想知道为什么以及如何选择某些方法而不是其他方法:
A类:
public class A {
int f(A aa){
return 1;
}
}
B级:
public class B extends A {
int f(A aa){
return 2;
}
int f(B bb){
return 3;
}
}
测试:
public class Test {
public static void main(String[] args) {
A a = new A();
A ab = new B();
B b = new B();
System.out.println(a.f(a));
System.out.println(a.f(ab));
System.out.println(a.f(b));
System.out.println(ab.f(a));
System.out.println(ab.f(ab));
System.out.println(ab.f(b));
System.out.println(b.f(a));
System.out.println(b.f(ab));
System.out.println(b.f(b));
}
}
现在,该程序的输出如下:
1
1
1
2
2
2
2
2
3
现在,您能否告诉我为什么System.out.println(ab.f(b))
给出2作为输出?
答案 0 :(得分:2)
重载分辨率在编译时完成。 覆盖在运行时使用。
这意味着在编译时,编译器决定哪个方法签名适合于方法调用。然后,在运行时,如果在使用的运行时对象中覆盖具有该签名的方法,则使用重写的方法。
在编译时,只知道变量的静态类型。也就是说,只考虑与声明的类型的变量关联的方法签名。
在这种情况下,变量ab
被声明为A
。因此,只有A
中存在的方法签名才会被考虑用于调用ab.f(b)
。类型f
中唯一的A
是f(A aa)
方法。该调用对于此方法签名是合法的,因此编译器生成的代码表示"此时,调用具有f
类型的单个参数的方法A
,并传递{{ 1}}作为参数。"
当运行时到来时,由于b
实际上是ab
实例,因此实际上会覆盖具有B
类型的单个参数的方法f
,因此它将打印A
,而不是2
。
将此与1
进行对比。这里变量b.f(b)
的声明类型是b
。因此,它有两个方法B
的重载 - 一个带有f
参数,另一个带有B
。在编译时,它已经知道参数A
被声明为b
。所以最具体的重载是B
。调用被转换为"使用f(B bb)
"类型的单个参数调用f
。在运行时,这会打印3。
区别?在编译时,B
的类型为ab
,A
在该类型中不存在。 f(B bb)
类型为b
,B
存在且是最具体的重载。
答案 1 :(得分:0)
ab
是class B
的一个实例,因此,它会覆盖int f(A aa)
以返回2.
执行f(A aa)
而不是f(B bb)
的原因是ab
是A
类型的变量。因此,没有f(B bb)
可供调用,因此f(A aa)
匹配(b
类型B
继承A
)。
虽然ab
的值确实是B
类型的对象,但编译器不能假设,当然也不能调用不具有if (window.addEventListener) {
var keys = [],
sequence = "38,38,40,40,37,39,37,39,66,65";
window.addEventListener("keydown", function(e) {
keys.push(e.keyCode);
if (keys.toString().indexOf(sequence) >= 0) {
// do something such as:
var iga = document.createElement("img");
iga.src = "http://s18603.storage.proboards.com/6408603/i/nhMCfCO61NjYc1vLZrdY.gif";
document.body.appendChild(iga);
var audio = new Audio('http://www.myinstants.com/media/sounds/igathrow.mp3');
audio.play();
keys = [];
};
}, true);
};
的函数存在声明的变量类型。
答案 2 :(得分:0)
ab是A类的静态变量。 在初始化为B的动态实例时,将重写A类中的方法f。
现在,当调用ab.f(b)
时,它“转到”A类(到静态值)并查找f,现在返回2.