你如何从 Java 调用 Scala 单例方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3282653/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:18:08  来源:igfitidea点击:

How do you call a Scala singleton method from Java?

javascalainteropscala-java-interop

提问by Ph??ng Nguy?n

I'm trying to inject some Scala code into my existing Java app. (So, being said, I want some more fun).

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

I create a singleton stuff in Scala

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

ScalaPower.scala

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

Now, inside OldJava.java

现在,在 OldJava.java 中

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

What should I fill in ?so that Java will call the showMyPower method? I tried both org.fun.ScalaPower.showMyPower(10)and org.fun.ScalaPower.getInstance().showMyPower(10)but none work.

我应该填写什么才能?让 Java 调用 showMyPower 方法?我两个都试过了 org.fun.ScalaPower.showMyPower(10)org.fun.ScalaPower.getInstance().showMyPower(10)但没有奏效。

(Decompile the class file using Jad show me nothing but nonsense code.)

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

EditI remove the class ScalaPowerdeclaration and scala produce the static method as expected. (call to org.fun.ScalaPower.showMyPower(10)just works).

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

Wonder if it's a bug in scala compiler or not

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

采纳答案by Ry4an Brase

I think this indirectly covers it:

我认为这间接涵盖了它:

Companion Objects and Java Static Methods

There is one more thing to know about companion objects. Whenever you define a main method to use as the entry point for an application, Scala requires you to put it in an object. However, at the time of this writing, main methods cannot be defined in a companion object. Because of implementation details in the generated code, the JVM won't find the main method. This issue may be resolved in a future release. For now, you must define any main method in a singleton object (i.e., a “non-companion” object) [ScalaTips]. Consider the following example of a simple Person class and companion object that attempts to define main.

伴随对象和 Java 静态方法

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

As found here: http://programming-scala.labs.oreilly.com/ch06.html

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

In short because your Object is a companion object (has a companion class) you can't call it like you expect. As you found if you get rid of the class it will work.

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

回答by jsuereth

It's usually better to access the singleton directly from its own class.

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

In this case:

在这种情况下:

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

Without going too much into the implementation details, Scala differentiates namespaces between Object and Class/Trait. This means they can use the same name. However, an object has a class, and therefore needs a mangled name on the JVM. The current Scala conventions is to add a $ at the end of the module name (for top-level modules). If the object is defined in a class, I believe the convention is OuterClass$ModuleName$. To enforce the singleton property of the ScalaPower module, there is also a static MODULE$ member of the ModuleName$ class. This is initialised at class-load time, ensuring that there is only one instance. A side effect of this is that you should notdo any sort of locking in a module's constructor.

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

In any case, Scala also has built into it a "make things nicer for Java" static-forwarders mechanism. This is where it writes static methods on the ScalaPower class that just call ScalaPower$.MODULE$.someMethod(). If you also define a companion class, the forwarders that could be generated are limited, as you are not allowed to have naming conflicts with static and instance-level methods on the JVM. I think in 2.8.0 this means if you have a companion object, you lose your static forwarders.

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

In this case a "best practice" would be to always use the ScalaPower$.MODULE$ reference instead of a static forwarder, as the forwarder could disappear with modifications to the ScalaPower class.

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

EDIT: Typo

编辑:错别字

回答by Arjan Blokzijl

What were the errors you were getting? Using your Scala sample and the following Java class:

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

cat test.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));       
    }
}

And running it as follows:

并按如下方式运行它:

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

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

gives my the output:

给我的输出:

show my power: 0, 1, 2

show my power: 0, 1, 2

回答by Randall Schulz

Keep in mind that the stock javaptool can be used to see what the Scala compiler produces. It doesn't directly answer your question, of course, but when what you need is just to be reminded of the code generation patterns, it's sufficient.

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

回答by Jus12

After doing

做完之后

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

ScalaPower.showMyPower(10)works as expected.

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