2016-09-05 6 views
0

Создал класс A, который расширяет класс B, который принимает два параметра.Scala reflection - конструктор не называется

Когда я создаю объект класса A с использованием отражения и передавая два параметра, объект создается без какого-либо исключения, но два параметра «конструктор» не содержат значений, которые я передал. Является ли это предполагаемым поведением или я делаю что-то неправильно?

Пример кода:

class B (p1: Int = 0, p2: String = "") { 
... 
} 

class A extends B { 
... 
} 


val mirror = universe.runtimeMirror(getClass.getClassLoader) 
val classSymbol = mirror.classSymbol(Class.forName("package.A")) 
val constructor = mirror.reflectClass(classSymbol).reflectConstructor(
       classSymbol.toType.decl(universe.termNames.CONSTRUCTOR).asMethod) 
val object: B = constructor(1, "C").asInstanceOf[B] 

"объект" содержит экземпляр А, но с P1 = 0 и P2 = "". Я ожидал, что он будет содержать p1 = 1 и p2 = "C".

Если я переведу (p1: Int = 0, p2: String = "") в A, он работает должным образом.

Является ли это нормальным поведением, и мои ожидания были просто неправильными, или есть ошибка в моем коде?

+0

Если 'A extends B' предоставил предоставленную вами реализацию, вы должны предоставить параметры конструктора для' B'. – sebszyller

+0

Конструктор для 'A' даже не принимает никаких аргументов. Если вы попытаетесь сделать это без отражения, вы получите ошибку компиляции. Не знаете, почему вы получаете значения по умолчанию вместо ошибки времени выполнения. –

ответ

1

Давай из картины полностью, и просто стараемся делать то, что вы делаете без отражения:

class B(p1: Int = 0, p2: String = "") 

class A extends B 

//val b = (new A(1, "C")).asInstanceOf[B] 

// even simpler: 
val b = new A(1, "C") 
// error: too many arguments for constructor A:()A 
//  new A(1, "C") 
//  ^

Как вы можете видеть, оно даже не компилируется. Зачем? Ну, вы определили конструктор A, чтобы не принимать никаких аргументов! Так или иначе, во время процесса отражения эта информация теряется, и вы заканчиваете законным вызовом, передавая аргументы конструктору, который не принимает и просто игнорирует их.

1

Я не знаю причину, но, вероятно, это связано с некоторой причудой в том, как отражение работает во время выполнения.

В любом случае этот код даст вам то, что вы хотите (без повторения значений по умолчанию, указанных в суперклассе). Обратите внимание, что вы должны явно указать параметры из суперкласса вы используете в подклассе:

class B (p1: Int = 0, p2: String = "") { 
    override def toString: String = s"p1 = $p1, p2 = $p2" 
} 

class A (p1: Int, p2: String) extends B (p1, p2) { } 

... 

val obj: B = constructor(1, "C").asInstanceOf[B] 
println(obj) 

Выход: первые отражения принимают

p1 = 1, p2 = C 
Смежные вопросы