如何使用反射调用Scala对象方法?

36

假设我有以下内容:

trait SomeTrait {
  def someMethod: String;
}

object SomeObject extends SomeTrait {
  def someMethod = "something";
}

我希望使用反射调用“someMethod”,因为我有一个对象名称作为字符串。 类似这样:

val objectName = "SomeObject"  
val someTrait:SomeTrait = ???.asInstanceOf[SomeTrait]  
someTrait.someMethod
或者类似的东西。
谢谢。
3个回答

25
def companion[T](name : String)(implicit man: Manifest[T]) : T = 
    Class.forName(name + "$").getField("MODULE$").get(man.erasure).asInstanceOf[T]

val result = companion[SomeTrait]("SomeObject").someMethod

这甚至更好。谢谢Thomas。 - sanjib
2
你需要清单文件吗?我发现 Class.forName(name + "$").getField("MODULE$").get(null) 就足够了。这适用于静态字段。 - 0__
3
2.10版本中使用反射如何进行翻译? - bhericher
使用Scala 2.10.2,我的代码在Class.forName(name + "$").getField("MODULE$")处抛出了异常。 - Kevin Meredith
@Thomas Jung,这里的“$”是什么意思?它指代什么?抱歉我对Scala还不熟悉。 - BdEngineer

20

从Scala 2.10开始,我们可以使用模块的反射:

import scala.reflect.runtime.universe

val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
val module = runtimeMirror.staticModule("SomeObject")
val obj = runtimeMirror.reflectModule(module)
val someTrait:SomeTrait = obj.instance.asInstanceOf[SomeTrait]  
someTrait.someMethod

15

对于类来说,可以使用标准的Java反射classOf方法轻松完成。对于Scala对象,需要做更多的工作,但仍然可以完成:


trait SomeTrait { def someMethod: String}
object SomeObject extends SomeTrait { def someMethod = "something"}

class SomeClass extends SomeTrait { def someMethod = "something"}

object Main {
 def main(args:Array[String]) = {
    val someClassTrait:SomeTrait = Class.forName("SomeClass").newInstance().asInstanceOf[SomeTrait]
    println("calling someClassTrait: " + someClassTrait.someMethod)
    val objectName = "SomeObject$"
    val cons = Class.forName(objectName).getDeclaredConstructors(); 
    cons(0).setAccessible(true);
    val someObjectTrait:SomeTrait = cons(0).newInstance().asInstanceOf[SomeTrait]
    println("calling someObjectTrait: " + someObjectTrait.someMethod)
  }
}

//prints:
calling someClassTrait: something
calling someObjectTrait: something

2
如果您创建了它的新实例,我认为这确实会打破客户对伴随对象(单例)的期望。 - Thomas Jung
Arjan - 谢谢。这正是我在寻找的。Thomas - 这是真的。但你可以将代码放入对象工厂中,并自己提供单例行为。 - sanjib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接