我将这个工作代码放在一起,动态地实例化给定name: String
(下面)的类。这适用于容易的case - 具有一个构造函数的类和case类。
我不知道如何处理存在多个构造函数的一般情况。我认为它们只能通过它们的签名来区分,但是发现伴随对象,类和案例类之间的概念交互有点令人困惑。什么是所有"建筑"的完整描述?需要考虑的场景,或者,您将如何将其演变为完全通用?
证明它的不灵活性,这段代码难以通过伴侣对象。
希望这段代码能够提供方便的测试和测试。如果有人关心加入这个思想训练,那就是修补流。
import scala.reflect.runtime.universe
case class CaseClass(foo: Int) {
println(s"${getClass.getSimpleName} Instantiated with $foo")
}
class BaseClass(foo: Int) {
println(s"${getClass.getSimpleName} Instantiated with $foo")
}
object BaseClass {
def apply(foo:Int) = {
println(s"going through companion object ${getClass.getSimpleName}")
new BaseClass(foo+10) }
}
class GenericClass[T](foo: T) {
println(s"${getClass.getSimpleName} Instantiated with $foo")
}
object Inst {
private def log(s: String) = println(Console.YELLOW + Console.BOLD + s + Console.RESET)
private def selectConstructor(symbol: universe.Symbol) = {
val constructors = symbol.typeSignature.members.filter(_.isConstructor).toList
if (constructors.length > 1) log(
s"""Warning: $symbol has several constructors, arbitrarily picking the first one:
| ${constructors.mkString("\n ")}""".stripMargin)
constructors.head.asMethod
}
def apply(className: String, arg: Any) = {
val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader)
val classSymbol: universe.ClassSymbol = runtimeMirror.classSymbol(Class.forName(className))
val classMirror: universe.ClassMirror = runtimeMirror.reflectClass(classSymbol)
if (classSymbol.companion.toString() == "<none>") // TODO: use nicer method "hiding" in the api?
{
log(s"Info: $className has no companion object")
val constructorMirror = classMirror.reflectConstructor(selectConstructor(classSymbol)) // we can reuse it
constructorMirror(arg)
}
else
{
val companionSymbol = classSymbol.companion
log(s"Info: $className has companion object $companionSymbol")
val constructorMirror = classMirror.reflectConstructor(selectConstructor(classSymbol)) // we can reuse it
constructorMirror(arg)
}
}
}
object Test extends App {
val c1 = Inst("BaseClass", 3)
val c2 = Inst("BaseClass", 4)
val cc = Inst("CaseClass", 5)
val gc1 = Inst("GenericClass", "I am generic")
val gc2 = Inst("GenericClass", gc1)
println(s"""\nthese objects have been instantiated:\n${List(c1,c2,cc,gc1,gc2).mkString("\n")}""")
}
请注意,它需要此build.sbt
或类似的:
lazy val reflection = (project in file("."))
.settings(
scalaVersion := "2.11.7",
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
"org.scala-lang" % "scala-library" % scalaVersion.value % "provided"
)
)