Scala反思:如何在给定“字符串类型”类名和方法名的情况下构造对象并运行其方法?

时间:2019-07-18 14:10:14

标签: scala reflection scala-reflect

给定第三方库中的类,方法和参数的名称,如何使用scala反射创建对象并调用其方法?

例如,类名称为“ 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类怎么办?

2 个答案:

答案 0 :(得分:1)

尝试

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)

答案 1 :(得分:1)

我必须同意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: _*)