2010-07-19 57 views
21

我正在尝试将一些Scala代码注入到我现有的Java应用程序中。 (所以,据说,我想要更多乐趣)。如何从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),但都没有工作。

(使用反编译亚德类文件告诉我什么,但废话代码。)

编辑 我删除class ScalaPower声明和Scala产生的静态方法如预期。 (致电org.fun.ScalaPower.showMyPower(10)只是工作)。

不知道是否是在Scala编译器错误或不

+1

什么'org.fun.ScalaPower.showMyPower(10)'? – OscarRyz 2010-07-19 16:55:01

+0

哎哟,我的坏。忘了更改名称空间。已经更新了这个问题。谢谢。 – 2010-07-20 06:34:50

+1

顺便说一下,你可以写'0直到时间'而不是'0到时间1'。 – 2011-02-10 08:27:37

回答

9

我认为这间接地覆盖它:

伴侣对象和Java静态 方法

有一两件事要了解 伴侣的对象。每当你定义一个主要方法 作为条目 指向一个应用程序,斯卡拉 要求你把它放在一个对象。 但是,在撰写本文时, 主要方法无法在 伴随对象中定义。由于 生成的代码中的 实现细节,JVM将找不到 主要方法。在未来的版本中可能会解决此问题 。目前, 您必须在一个 单例对象(即,一个 “非伴随”对象)[ScalaTips]中定义任何主要方法。 考虑下面的示例,该示例试图定义main的 简单Person类和伴随 对象。

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

总之,因为你的对象是一个同伴对象(有一个伴侣应用类)就像你期望你不能调用它。正如你发现,如果你摆脱了课程,它会起作用。

+2

这不再是事实。在写作时和斯卡拉2之间。8发布后,转发代码生成模式被固定,以允许在同伴中使用主要方法。 – 2010-07-20 15:23:35

+0

哦,非常好。这本书暗示他们希望它会被改变,但没有说2.8(他们很期待2.8-ness)。 这就是说原始的提问者没有给他的版本,并从他的“编辑我删除类ScalaPower声明和Scala产生预期的静态方法。”它仍然听起来可能是这个问题。 – 2010-07-20 16:46:33

+0

谢谢。这解释了我的情况。我现在正在转换到scala 2.8。地狱,eclipse scala插件仍然很糟糕。 – 2010-07-20 17:57:08

3

请记住,股票javap工具可以用来查看Scala编译器产生什么。当然,它并不直接回答你的问题,但是当你需要的是提醒代码生成模式时,这就足够了。

+0

谢谢。当我回家时我会尝试。 (现在工作) – 2010-07-20 06:39:37

10

你得到的错误是什么? 使用您的斯卡拉样品和下面的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

+1

嗯,这很奇怪。我的代码甚至没有编译。它是说''符号'showMyPower'没有找到'(尽管IDEA Scala插件理解它,并提供了一个自动完成) – 2010-07-20 06:37:33

+0

我发现实际上'showMyPower'方法是在Scala $中声明的,而不是Scala。您正在使用哪个版本的Scala使这些代码可编译?我正在使用2.7.5 – 2010-07-20 12:45:18

+0

Ouch,'org.fun.ScalaPower $ .MODULE $ .showMyPower'确实是我应该调用的正确方法,那是什么? – 2010-07-20 12:56:35

1

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

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

14

通常直接从自己的类访问单身人士通常会更好。

在这种情况下:

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

没有去过多的实现细节,斯卡拉区分对象和类/性状之间的命名空间。这意味着他们可以使用相同的名称。但是,一个对象有一个类,因此需要在JVM上有一个重名的名称。当前的Scala约定是在模块名称末尾添加一个$(用于顶层模块)。如果该对象是在一个类中定义的,我相信这个约定是OuterClass $ ModuleName $。为了强制执行ScalaPower模块的单例属性,ModuleName $类还有一个静态MODULE $成员。这是在类加载时初始化的,确保只有一个实例。这样做的一个副作用是你应该在模块的构造函数中做任何类型的锁定,而不是而不是。在任何情况下,Scala还内置了一个“为Java创造更好的”静态转发机制。这就是它在ScalaPower类上写静态方法的地方,它只是调用ScalaPower $ .MODULE $ .someMethod()。如果您还定义了一个伴随类,那么可能会生成的转发器是有限的,因为您不允许在JVM上与静态和实例级方法命名冲突。我认为在2.8.0这意味着如果你有一个伴侣对象,你会失去静态转发器。

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

编辑:错字

+0

这里的代码在MODULE $中有一个错字 – 2013-11-29 17:23:54