26

我正在尝试将一些 Scala 代码注入到我现有的 Java 应用程序中。(所以,有人说,我想要更多的乐趣)。

我在 Scala 中创建了一个单例的东西

ScalaPower.scala

    package org.fun
    class ScalaPower
    object ScalaPower{
      def showMyPower(time:Int) = {
        (0 to time-1).mkString(", ")
      }
    }

现在,在 OldJava.java 中

class OldJava {
  public void demo(){
    System.out.println(?)
  }
}

我应该填写什么?以便 Java 调用 showMyPower 方法?我都试过了 org.fun.ScalaPower.showMyPower(10)org.fun.ScalaPower.getInstance().showMyPower(10)但都没有。

(使用 Jad 反编译类文件只显示无意义的代码。)

编辑 我删除了class ScalaPower声明,scala按预期生成了静态方法。(调用org.fun.ScalaPower.showMyPower(10)只是有效)。

想知道这是否是 scala 编译器中的错误

4

5 回答 5

22

通常最好直接从它自己的类中访问单例。

在这种情况下:

org.fun.ScalaPower$.MODULE$.showMyPower(10);

Scala 没有过多介绍实现细节,而是区分了 Object 和 Class/Trait 之间的命名空间。这意味着他们可以使用相同的名称。但是,一个对象有一个类,因此在 JVM 上需要一个错位的名称。当前的 Scala 约定是在模块名称的末尾添加一个 $(对于顶级模块)。如果对象是在一个类中定义的,我相信约定是 OuterClass$ModuleName$。为了强制 ScalaPower 模块的单例属性,ModuleName$ 类还有一个静态 MODULE$ 成员。这是在类加载时初始化的,确保只有一个实例。这样做的副作用是您不应该模块的构造函数中进行任何类型的锁定。

无论如何,Scala 还内置了一个“让 Java 变得更好”的静态转发器机制。这是它在 ScalaPower 类上编写静态方法的地方,这些方法只调用 ScalaPower$.MODULE$.someMethod()。如果您还定义了伴随类,则可以生成的转发器是有限的,因为您不允许与 JVM 上的静态和实例级方法发生命名冲突。我认为在 2.8.0 中,这意味着如果你有一个伴随对象,你就会失去你的静态转发器。

在这种情况下,“最佳实践”是始终使用 ScalaPower$.MODULE$ 引用而不是静态转发器,因为转发器可能会随着对 ScalaPower 类的修改而消失。

编辑:错字

于 2010-08-10T02:22:31.790 回答
10

你遇到了什么错误?使用您的 Scala 示例和以下 Java 类:

cat test.java


import org.fun.*;

public class test {
    public static void main(String args[]) {
       System.out.println("show my power: " + ScalaPower.showMyPower(3));       
    }
}

并按如下方式运行:

java -cp .:<path-to/scala/install-dir>/lib/scala-library.jar test

给我的输出:

show my power: 0, 1, 2

于 2010-07-19T16:45:13.817 回答
10

我认为这间接涵盖了它:

伴随对象和 Java 静态方法

关于伴生对象,还有一件事需要了解。每当您定义一个 main 方法用作应用程序的入口点时,Scala 都要求您将其放入对象中。但是,在撰写本文时,无法在伴随对象中定义主要方法。由于生成代码中的实现细节,JVM 不会找到 main 方法。此问题可能会在未来的版本中得到解决。现在,您必须在单例对象(即“非伴随”对象)[ScalaTips] 中定义任何主方法。考虑以下尝试定义 main 的简单 Person 类和伴随对象的示例。

在这里找到:http: //programming-scala.labs.oreilly.com/ch06.html

简而言之,因为您的 Object 是一个伴生对象(有一个伴生类),所以您不能像您期望的那样调用它。正如您发现的那样,如果您摆脱课程,它将起作用。

于 2010-07-20T14:56:52.710 回答
3

请记住,stockjavap工具可用于查看 Scala 编译器生成的内容。当然,它不会直接回答您的问题,但是当您需要的只是提醒代码生成模式时,这就足够了。

于 2010-07-19T16:13:41.767 回答
1

做完之后

class ScalaPower 
object ScalaPower{
  def showMyPower(time:Int) = {
    (0 to time-1).mkString(", ")
  }
}

ScalaPower.showMyPower(10)按预期工作。

于 2010-08-09T21:03:59.723 回答