3

我正在编写 Java(不是 Scala)代码,其中有一个 JavaClass参考,指的是 Scala 类型T

trait T {}

我现在想通过仅使用 Java 反射来发现 JavaClass引用和对应的单例实例,object T然后调用该伴随对象中的方法。

object T {
  def someMethod : String = "abc";
}

我对生成的 Scala 代码进行了逆向工程,以编写以下 Java 代码:

Class<?> traitClass = ...;
Class<?> companionClass = Class.forName(traitClass.getName() + "$");
Field module = companionClass.getField("MODULE$");
Object companion = module.get(companionClass);
String abc = (String) companionClass.getMethod("someMethod").invoke(companion);

这看起来不是很健壮——它可能会随着未来的 Scala 编译器随时改变。有没有更健壮的方法?我也愿意调用 Scala API(来自 Java)来发现伴随实例。

4

1 回答 1

2

您编写的代码适用于顶级(包拥有)同伴。它也适用于嵌套类/特征-对象对的基本情况,但有些情况下简单name + $方案不成立。这是和示例:

class C {
  class D
  object D
  def foo() {
    class K
    object K
  }
}

这将生成类文件CC$DC$D$和.C$K$2C$K$3$

虽然编码可能在未来的任何时间发生变化,但它在很长一段时间内都没有改变,也没有计划改变。我刚试过2.5.0,除了嵌套在方法中的类之外,类名都是一样的。

如果您可以控制 Scala 类,那么简单的方法是def companion = T向 trait添加一个方法T

另一种选择是使用 Scala 反射 API:

scala> import scala.reflect.runtime.{universe => ru}
scala> val m = ru.runtimeMirror(getClass.getClassLoader)

scala> val d = classOf[C$D]
d: Class[C$D] = class C$D

scala> m.runtimeClass(m.classSymbol(d).companionSymbol.asModule.moduleClass.asClass)
res16: Class[_] = class C$D$

但这在嵌套在方法中的类上也不能按预期工作:

scala> val k = classOf[C$K$2]
k: Class[C$K$2] = class C$K$2

scala> m.classSymbol(k).companionSymbol
res2: reflect.runtime.universe.Symbol = <none>

请注意,在 SO 上搜索“scala 反射伴侣”也会产生几个结果(并显示一些问题)。

于 2016-03-18T08:28:31.003 回答