鉴于以下代码
class Parent {
def mth(p1: Int = 1, p2: Int = 2) = p1 + p2
}
class Child extends Parent{
override def mth(p2: Int = 10, p1: Int = 20) = super.mth(p2, p1)
}
object Main {
def main(args: String[]) = {
val parentRefToChild: Parent = new Child
println(parentRefToChild.mth(p1=1)) // 21
}
}
输出是
21
,但我认为应该是11
。在检查编译的.class文件时,我发现parentRefToChild.mth(p1=1)
被编译为parentRefToChild.mth(1, parentRefToChild.mth$default$2())
。 Scala编译器如何以这种方式表现。 最佳答案
这里的问题是您更改了Child
中的参数顺序:
override def mth(p2: Int = 10 , p1: Int = 20)
因此,在
mth
类中为Child
生成的综合方法将类似于:def mth$default$1 = 10 // generated method for p2 in Child
def mth$default$2 = 20 // generated method for p1 in Child
当您在
mth
类引用上调用Parent
时,将使用静态类型检查来确定参数是否具有默认值。在这里,静态类型检查将在Parent
上进行,因为parentRefToChild
是Parent
类型。因此,当遇到
parentRefToChild.mth(p1=1)
时,此时编译器不知道parentRefToChild
实际上是在保存Child
类实例。它只是尝试匹配mth
类中的Parent
的签名。现在,在这里看到提供了p1
的值,但是p2
丢失了,并且具有默认值,它只是将parentRefToChild.mth(p1=1)
替换为:parentRefToChild.mth(1, parentRefToChild.mth$default$2())
现在在运行时,从
mth$default$2()
类中选择合成方法Child
(因为parentRefToChild
持有Child
的实例),然后将其转换为:parentRefToChild.mth(1, 20)
因此,您得到
21
作为输出。