子类型和超类型、方法和转换
Sub- and Supertypes, Methods, and Conversion
我目前正在阅读 Barbara Liskov 相当不错的第二版 程序开发 Java:抽象、规范和面向对象设计 (2000)研究生课程。作为参考,对于这个问题,我正在查阅第 2.4.2 节:转换和重载(第 27-29 页)。 Liskov 正在讨论方法重载以及在为重载调用提供实际参数时 Liskov 所说的编译器对“'most specific'”(第 28 页)方法的识别。
下面是 Liskov 提供的重载方法的例子 foo
:
void foo (T a, int x) // defn. 1
void foo (S b, long y) // defn. 2
下面的调用 - Liskov 指出不合法:
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 页)。
为什么我错了?我有什么不明白的?
所以,我向我的一个计算机科学伙伴展示了这个问题。而且,现在我知道了答案,我觉得自己像个傻瓜(他问我这个问题,"Yeah, it's legal; but, how does the compiler know which method to call?");然而 - 既然我已经度过了我的 'Oh, duh!' 时刻 - 我认为答案仍然对那些暂时陷入与我相同的位置的人有帮助:
这里,问题不是调用的合法性(如果//defn. 1
是唯一可用的方法,调用将是绝对合法的)。这是一个问题 - 如上面的问题所述 - "most specific" 而对象 e
不是问题。
类型int
的实际参数3
是问题所在。
为什么? int
合法扩展为类型 long
;因此,编译器不知道调用哪个方法,因为两个调用都可以接收这些实际参数。
我目前正在阅读 Barbara Liskov 相当不错的第二版 程序开发 Java:抽象、规范和面向对象设计 (2000)研究生课程。作为参考,对于这个问题,我正在查阅第 2.4.2 节:转换和重载(第 27-29 页)。 Liskov 正在讨论方法重载以及在为重载调用提供实际参数时 Liskov 所说的编译器对“'most specific'”(第 28 页)方法的识别。
下面是 Liskov 提供的重载方法的例子 foo
:
void foo (T a, int x) // defn. 1
void foo (S b, long y) // defn. 2
下面的调用 - Liskov 指出不合法:
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 页)。
为什么我错了?我有什么不明白的?
所以,我向我的一个计算机科学伙伴展示了这个问题。而且,现在我知道了答案,我觉得自己像个傻瓜(他问我这个问题,"Yeah, it's legal; but, how does the compiler know which method to call?");然而 - 既然我已经度过了我的 'Oh, duh!' 时刻 - 我认为答案仍然对那些暂时陷入与我相同的位置的人有帮助:
这里,问题不是调用的合法性(如果//defn. 1
是唯一可用的方法,调用将是绝对合法的)。这是一个问题 - 如上面的问题所述 - "most specific" 而对象 e
不是问题。
类型int
的实际参数3
是问题所在。
为什么? int
合法扩展为类型 long
;因此,编译器不知道调用哪个方法,因为两个调用都可以接收这些实际参数。