2016-05-23 6 views
2

Учитывая приведенный ниже кодScala: переопределение именованного параметр

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 вести себя так.

ответ

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 «s экземпляр), который затем превращается в:

parentRefToChild.mth(1, 20)

Таким образом, вы получаете 21, как вывод.

Смежные вопросы