Scala 反射:如何在给定 'String-type' class 名称和方法名称的情况下构造对象和 运行 其方法?

Scala reflection: How to construct object and run its methods given 'String-type' class name and method name?

给定一个class的名称,方法和来自第三方库的参数,如何使用scala反射创建一个对象并调用它的方法?

例如class名称为"org.apache.spark.mllib.clustering.LDA",方法为"setK",参数为3,如何使用scala反射构造LDA对象并调用方法?结果应等同于 new LDA().setK(3).

在scala反射文档中,我找到了下面的代码来构造一个Person对象

val m = ru.runtimeMirror(getClass.getClassLoader)
val classPerson = ru.typeOf[Person].typeSymbol.asClass
val ctor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod
val ctorm = cm.reflectConstructor(ctor)
val p = ctorm("Mike")

但是如果我有 "Person" 而不是 Person class 怎么办?

尝试

import org.apache.spark.mllib.clustering.LDA
import scala.reflect.runtime.{universe => ru}

val m = ru.runtimeMirror(getClass.getClassLoader)
val classLDA = ru.typeOf[LDA].typeSymbol.asClass
val ctor = ru.typeOf[LDA].decl(ru.termNames.CONSTRUCTOR).asMethod
val cm = m.reflectClass(classLDA)
val ctorm = cm.reflectConstructor(ctor)
val p = ctorm.asInstanceOf[LDA]
p.setK(3)

我必须同意 Luis 的评论,您应该认真考虑其他方法,但如果这确实是您需要的:

// for the example
val className = "org.apache.spark.mllib.clustering.LDA"
val methodName = "setK"
val constructorParams = Array()
val params = Array(3)

// symbols
val m = ru.runtimeMirror(getClass.getClassLoader)
val classSymbol = m.staticClass(className)
val ctor = classSymbol.primaryConstructor.asMethod
// assumes the method exists and isn't overloaded
val method = classSymbol.toType.decl(ru.TermName(methodName)).asMethod

val cm = m.reflectClass(classSymbol)
val ctorm = cm.reflectConstructor(ctor)

val instance = ctorm(constructorParams: _*)
val instancem = m.reflect(instance)
val methodm = instancem.reflectMethod(method)

methodm(params: _*)

或者对于这个特定的任务,您会发现使用 Java 反射更简单,而 Scala 反射没有提供真正的优势:

val clazz = Class.forName(className)
val ctor = clazz.getConstructors()(0)
val instance = ctor.newInstance(constructorParams: _*)
// again, assumes the method exists and isn't overloaded
val method = clazz.getMethods().find(_.getName == methodName).get
method.invoke(instance, params: _*)