考虑这个Scala代码:
class X {
def m(a:A) = a.f(this) + ", " + "m(a:A) in X"
}
class Y extends X {
override def m(a:A) = a.f(this) + ", " + "m(a:A) in Y"
}
class Z extends Y
class A {
def f(x:X):String = "f(x:X) in A"
def f(y:Y):String = "f(y:Y) in A"
}
class B extends A {
override def f(x:X):String = "f(x:X) in B"
def f(z:Z):String = "f(z:Z) in B"
def g(x:X):String = super.f(x) + ", " + "g(x:X) in B"
def h(y:Y):String = B.g(y) + ", " + "h(y:Y) in B"
}
object B {
def f(x:X) = "f(x:X) in ObjB"
def g(y:Y) = f(y) + ", " + "g(y:Y) in ObjB"
def g(z:Z) = f(z) + ", " + "g(z:Z) in ObjB"
}
class C extends B {
override def f(y:Y):String = "f(y:Y) in C"
def h(z:Z):String = super.h(z) + ", " + "h(z:Z) in C"
def k(x:X):String = x.m(this) + ", " + "k(x:X) in C"
}
给出的问题是:给出运行以下程序的输出:
val z: Z = new Z; val x: X = new Y
val c: C = new C; val a: A = new B
println(a.f(x)); println(a.f(z))
println(c.g(z)); println(c.h(z))
println(c.k(x))
我似乎无法完全理解给出的输出。这就是我认为发生的事情:
println(a.f(x)) = "f(x:X) in B"
println(a.f(z)) = "f(z:Z) in B"
println(c.g(z)) = "f(y:Y) in A, g(x:X) in B"
println(c.h(z)) = "f(y:Y) in A, g(y:Y) in ObjB, h(y:Y) in B, h(z:Z) in C"
println(c.k(x)) = "f(y:Y) in C, m(a:A) in Y, k(x:X) in C"
然而,当我实际将代码放入REPL时,我得到了不同的结果:
println(a.f(x)) = "f(x:X) in B"
println(a.f(z)) = "f(y:Y) in A"
println(c.g(z)) = "f(x:X) in A, g(x:X) in B"
println(c.h(z)) = "f(x:X) in ObjB, g(y:Y) in ObjB, h(y:Y) in B, h(z:Z) in C"
println(c.k(x)) = "f(y:Y) in C, m(a:A) in Y, k(x:X) in C"
这是为什么?我知道这与如何选择重载方法有关,但我找不到一个精确指定如何确定选择哪些方法的单一资源,以及何时。如果有人能解释确切的过程,我将不胜感激。
答案 0 :(得分:3)
我不认为这与线性化有关,因为示例中没有多重继承。此示例与方法overriding和overloading一起发送。
首先我们需要分开"实际类型"和"声明的类型"。适用于
中的检验val x: X = new Y
变量x
声明类型为X
,实际类型为Y
。您无法更改值的实际类型,但如果它们是超类型,您可以将某些实际类型的值分配给不同声明类型的变量。
调用分派有一个简单(和简化)规则:对于首先调度的方法重载,即当一个对象作为参数传递时,其声明的类型用于选择方法;对于方法重写,即在对象上调用方法时,其实际类型用于选择方法。
附加规则this
始终声明声明它的类的类型。
此外,您还应该学习如何调试应用程序。调试很容易显示调用哪些方法。
<强>类型强>
在
val x: X = new Y
val z: Z = new Z;
val a: A = new B
val c: C = new C;
x
已声明类型为X
且实际类型为Y
z
包含Z
a
已声明类型为A
且实际类型为B
c
包含C
示例#1是微不足道的,所以我将省略它。
<强>#2 强>
println(a.f(z)) = "f(y:Y) in A"
这里我们首先需要解决重载,即在类型A
方法中查找接受最接近Z
的类型。它是
def f(y:Y):String = "f(y:Y) in A"
现在我们需要调度重写,即检查B
是否覆盖此方法且答案为否,B
中的方法没有覆盖,因此{{1}中的方法生成输出}}
A
&#39;
B
未选择的是def f(z:Z):String = "f(z:Z) in B"
声明 类型a
,因此A
更具体方法在此上下文中不可见。
<强>#3 强>
B
这里我们首先需要解决重载,即在类型println(c.g(z)) = "f(x:X) in A, g(x:X) in B"
方法中查找接受最接近C
的类型。这是Z
&#39>
B
我们可以看到def g(x:X):String = super.f(x) + ", " + "g(x:X) in B"
中没有覆盖此方法,因此它会产生输出。从C
super.f(x)
表示A.f(x)
<强>#4 强>
B extends A
这里我们首先需要解决重载,即在类型println(c.h(z)) = "f(x:X) in ObjB, g(y:Y) in ObjB, h(y:Y) in B, h(z:Z) in C"
方法中查找接受最接近C
的类型。这是Z
&#39>
C
这给了我们答案的最后部分。现在def h(z:Z):String = super.h(z) + ", " + "h(z:Z) in C"
表示super.h(z)
&#39;
B
因为def h(y:Y):String = B.g(y) + ", " + "h(y:Y) in B"
中没有h(Z)
所以我们需要搜索接受基本类型B
的方法。这使我们在答案的最后部分排在第二位。现在Z
是B.g(y)
object B
这是因为在def g(y:Y) = f(y) + ", " + "g(y:Y) in ObjB"
声明的类型为h(y:Y)
而非原始(和实际)Y
的上下文中。显然,此处Z
是f(y)
object B
<强>#5 强>
def f(x:X) = "f(x:X) in ObjB"
我们首先需要解决重载,即在类型println(c.k(x)) = "f(y:Y) in C, m(a:A) in Y, k(x:X) in C"
方法中查找接受最接近C
的类型。这是X
&#39>
C
这给了我们答案的最后部分。现在解决def k(x:X):String = x.m(this) + ", " + "k(x:X) in C"
:我们需要找到接受x.m(this)
最接近类型的X
方法m
:
C
但这是第一次 覆盖 的步骤。此处def m(a:A) = a.f(this) + ", " + "m(a:A) in X"
的实际类型为x
,因此调用将发送到{ {1}}&#39; S
Y
现在我们需要解决Y
。 override def m(a:A) = a.f(this) + ", " + "m(a:A) in Y"
此处声明的类型为a.f(this)
,所以
this
是Y
中的匹配,但def f(y:Y):String = "f(y:Y) in A"
覆盖了此方法,所以
A
将被选中。