我目前正在阅读Barbara Liskov第二版的非常好的 Java程序开发:抽象,规范和面向对象设计(2000),用于研究生课程。作为参考,我对于这个问题,请参阅第2.4.2节:转换和重载(第27-29页)。 Liskov正在讨论方法重载以及Liskov称编译器识别"'最具体的'" (第28页)为超载呼叫提供实际参数时的方法。
这里的示例Liskov提供了以下重载方法foo
:
void foo (T a, int x) // defn. 1
void foo (S b, long y) // defn. 2
接下来的电话 - 利斯科夫声称不合法:
o.foo(e, 3)
以下是我们对实际参数的了解:
S
是T的子类型。e
是S
在我看来,理论上这是一个合法的呼吁。调用o.foo(e, 3)
与使调用更具体相同(如果我在比较表观类型时考虑编译器):
o.foo((T) e, 3)
显然,e
只能在进行此调用时访问超类型的减少的常见行为;但是,它还不是一个合法的电话吗?
规模较小:
Object o = s
是合法的s
评估类型String
(仅仅是为了引用:Liskov,第26页)。
为什么我错了?我不理解的是什么?
答案 0 :(得分:0)
所以,我向我的计算机科学伙伴展示了这个问题。而且,现在我知道了答案,我觉得自己像个假人(他问我这个问题,"是的,它是合法的;但是,编译器如何知道要调用哪种方法?" );然而 - 现在我已经拥有了我的噢,呃!'那一刻 - 我认为答案仍然会对那些暂时陷入我所处位置的人有所帮助:
在这里,问题不在于呼叫的合法性(//defn. 1
是唯一可用的方法,呼叫绝对合法)。这是一个问题 - 如上面的问题中所述 - "最具体的"对象e
不是问题。
类型3
的实际参数int
是问题所在。
为什么呢? int
合法扩展为long
;因此,编译器不知道调用哪个方法,因为两个调用都可以接收这些实际参数。