鉴于以下代码
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编译器如何以这种方式运行。
答案 0 :(得分:5)
问题在于您更改了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
作为输出。