java - 通过 Java 反射找到 Scala 类型的伴随对象的可靠方法是什么?

标签 java scala reflection language-interoperability

我正在编写 Java(不是 Scala)代码,其中我有一个 Java Class 引用,指的是 Scala 类型 T:

trait T {}

我现在想通过Java反射发现Java Class引用,以及对应于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);

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

最佳答案

您编写的代码适用于顶级(包拥有的)同伴。它也适用于嵌套类/特征对象对的基本情况,但有些情况下简单的 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 reflection companion”也会产生几个结果(并显示一些问题)。

关于java - 通过 Java 反射找到 Scala 类型的伴随对象的可靠方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36068089/

相关文章:

java - 避免为每条记录重新初始化 groovy shell

sbt 发布的工件中的 scala-library.jar 版本

c# - 关于 .NET 中的反射的完整教程?

wsdl - 用于在句法上比较 WSDL 元素的 Java 库

java - 提交html表单数据到webflux HandlerFunction

scala - 有没有办法在 scala 2.8 中创建一个 IdentityMap

java - 为什么在 REPL 中没有观察到通配符类型和存在类型之间指定的等价性

java - 我需要列出使用 java.lang.ApplicationShutdownHooks 注册的钩子(Hook)

java - 使用Reflection API是否会使Java的安全性降低?

java - 通过二分查找查找数组中存储的信息