我该如何在Java中传递一个Scala对象引用?

11

我想从一个Java方法中返回一个对Scala对象的引用,我该怎么做?

我的Scala对象长这样:

trait Environment 

object LocalEnvironment extends Environment {...}
object ServerEnvironment extends Environment {...}

...我希望我的Java方法像这样:

Environment getEnvironment() { return LocalEnvironment; }  // DOES NOT COMPILE

有没有方法可以做到这一点?

2个回答

24

虽然 $.MODULE$ 方法可行,但更加平稳的获取Scala对象与Java互操作性的方法是将对象本身公开为一个方法。

Scala代码:

object LocalEnvironment extends Environment{
   def instance = this
}

Java:

Environment getEnvironment() { return LocalEnvironment.instance(); }  

这个方法能够正常工作是因为在底层,.instance() 是作为类 LocalEnvironment 的静态方法实现的。曾经有一些关于 Scala 对象默认获得 "instance" 方法的讨论,就是为了这个目的。


1
这很酷,但需要一些注释来解释变量的目的。因此,我选择了MODULE $。 - David
同意,很酷,+1,但只有在您对对象源具有写访问权限时才有效。例如,对于scala.xml.TopScope无效。 - Synesso

22
{ return LocalEnvironment$.MODULE$; }

应该可以工作。


编辑:这个方法能够工作的原因是Scala是如何表示单例对象的。类ObjectName$中有一个叫做MODULE$的字段,它用单个有效实例填充。但也有一个名为ObjectName的类,它将所有方法复制为静态方法。这样你就可以像Java一样使用它(只需调用ObjectName.methodName)在大多数情况下,而Scala则可以拥有一个真正的类来传递。

但当Java需要传递类时——这通常不是使用一堆静态方法所做的事情,而这正是object在Java中设计的模拟——你需要知道Scala在内部是如何表示它的。


1
能否解释一下?这是一种“可移植”的方法,还是$符号只是Scala的实现工件? - Brian Agnew
@Brian - 我在编辑中部分回答了你的问题。我不确定你所说的“可移植性”与“实现工件”的区别是什么。它们都是一样的——Scala为其实现工件使用一致的命名方案。与匿名闭包不同,这个很容易预测。 - Rex Kerr
鉴于 LocalEnvironment 似乎是一个独立的单例对象,应该将其更改为 return LocalEnvironment.MODULE$(在 LocalEnvironment 中不需要 $)。 - Fabian Steeg
1
@Fabian - 这样不行。LocalEnvironment 类将仅包含复制 Scala 单例中的(非静态)方法所需的那些静态方法。MODULE$ 不是其中之一 - 它是 LocalEnvironment$ 类的一个字段,在单个副本中实例化(即 LocalEnvironment$ 是包含实现细节的类,而 MODULE$ 是其中的一个实现细节)。 - Rex Kerr

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