简体   繁体   English

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

[英]How do you call a Scala singleton method from Java?

I'm trying to inject some Scala code into my existing Java app. 我试图将一些Scala代码注入到现有的Java应用程序中。 (So, being said, I want some more fun). (所以,话说回来,我想要更多的乐趣)。

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? 这样Java就会调用showMyPower方法? I tried both org.fun.ScalaPower.showMyPower(10) and org.fun.ScalaPower.getInstance().showMyPower(10) but none work. 我同时尝试了org.fun.ScalaPower.showMyPower(10)org.fun.ScalaPower.getInstance().showMyPower(10)org.fun.ScalaPower.getInstance().showMyPower(10)

(Decompile the class file using Jad show me nothing but nonsense code.) (使用Jad反编译类文件,除了胡说八道之外,什么都没给我显示。)

Edit I remove the class ScalaPower declaration and scala produce the static method as expected. 编辑我删除了class ScalaPower声明,并且scala产生了预期的静态方法。 (call to org.fun.ScalaPower.showMyPower(10) just works). (调用org.fun.ScalaPower.showMyPower(10)即可)。

Wonder if it's a bug in scala compiler or not 想知道这是否是scala编译器中的错误

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. 无需过多介绍实现细节,Scala可以将名称空间区分为对象和类/特质。 This means they can use the same name. 这意味着他们可以使用相同的名称。 However, an object has a class, and therefore needs a mangled name on the JVM. 但是,对象具有类,因此需要在JVM上使用错误的名称。 The current Scala conventions is to add a $ at the end of the module name (for top-level modules). 当前的Scala约定是在模块名称的末尾添加$(对于顶级模块)。 If the object is defined in a class, I believe the convention is OuterClass$ModuleName$. 如果对象是在类中定义的,则我相信约定是OuterClass $ ModuleName $。 To enforce the singleton property of the ScalaPower module, there is also a static MODULE$ member of the ModuleName$ class. 为了强制执行ScalaPower模块的singleton属性,在ModuleName $类中还有一个静态MODULE $成员。 This is initialised at class-load time, ensuring that there is only one instance. 这是在类加载时初始化的,以确保只有一个实例。 A side effect of this is that you should not do any sort of locking in a module's constructor. 这方面的一个副作用是,你应该做任何形式的模块构造锁定。

In any case, Scala also has built into it a "make things nicer for Java" static-forwarders mechanism. 无论如何,Scala还内置了一种“使Java变得更好”的静态转发器机制。 This is where it writes static methods on the ScalaPower class that just call ScalaPower$.MODULE$.someMethod(). 在这里,它在ScalaPower类上编写仅调用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. 如果您还定义了一个伴随类,则可以生成的转发器将受到限制,因为不允许您与JVM上的静态和实例级方法发生命名冲突。 I think in 2.8.0 this means if you have a companion object, you lose your static forwarders. 我认为在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 编辑:错别字

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

gives my the output: 给我的输出:

show my power: 0, 1, 2

I think this indirectly covers it: 我认为这间接地涵盖了它:

Companion Objects and Java Static Methods 伴侣对象和Java静态方法

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. 每当您定义一个主要方法用作应用程序的入口点时,Scala都会要求您将其放在一个对象中。 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. 由于生成的代码中有实现细节,因此JVM找不到主要方法。 This issue may be resolved in a future release. 以后的版本中可能会解决此问题。 For now, you must define any main method in a singleton object (ie, a “non-companion” object) [ScalaTips]. 现在,您必须在单例对象(即“非同伴”对象)[ScalaTips]中定义任何主要方法。 Consider the following example of a simple Person class and companion object that attempts to define main. 考虑以下尝试定义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. 如您所见,如果您摆脱了该类,它将起作用。

Keep in mind that the stock javap tool can be used to see what the Scala compiler produces. 请记住,可以使用javap工具来查看Scala编译器产生的内容。 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. 当然,它并不能直接回答您的问题,但是当您只需要提醒代码生成模式时,就足够了。

After doing 做完之后

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

ScalaPower.showMyPower(10) works as expected. ScalaPower.showMyPower(10)可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM