【问题标题】:How to declare scala method so that it can be called from Java using varargs style如何声明 scala 方法以便可以使用 varargs 样式从 Java 调用它
【发布时间】:2012-05-22 18:41:20
【问题描述】:

我在 Scala 库类中有 2 个简单的方法:

class Foo {
  def bar(args : String*) : Unit = println("Foo.bar with: " + args)
  def bar(args : Array[String]) : Unit = bar(args.toSeq : _*)
}

这一切都编译得很好。然后我将其放入库 foo.jar 并尝试编译以下 Java:

import Foo
public class Test {

    public static void main(String[] args) {
        Foo foo = new Foo();
        foo.bar("Hello", "World"); //DOES NOT COMPILE
    }
}

我可以将有问题的行替换为:

foo.bar(new String[] { "Hello", "World" }); //OK

但这似乎违背了这一点。如何使用 Java varargs-like 语法从 Java 调用它?

【问题讨论】:

  • 可能是拼写错误,但 Foo 类没有 foo 方法。
  • 我所说的显然是错误的,尽管我承认这让我感到困惑。我正在删除我的答案以避免传播错误信息。

标签: java scala interop variadic-functions


【解决方案1】:

在 2.8(不知道是 2.7)中,如果您从 Java 父级重写 varargs 方法,或者从 Java 接口实现 varargs 方法,那么 Scala 编译器将生成两种方法,一种用于 Scala,一种用于 Java。 Java 版本——正如您通过检查字节码自己看到的那样——只需获取 varargs 数组并将其包装,然后将 WrappedArray 传递给需要 Seq 的 Scala 版本。

如果有办法强制编译器在其他情况下生成转发器,我不知道。我怀疑它的存在。似乎提供一种方法来请求它(我猜是注释)将是一个合理的增强请求。

【讨论】:

    【解决方案2】:

    不完全确定,但我认为 Scala 中的可变参数使用序列并且与 java 实现不同。我认为完成您想要的最简单的方法是在 Java 中继承 Foo scala 类并添加一个采用 Java vararg 的 bar 方法,即

    public class JavaFoo extends Foo {
        public void bar(String... args) {
             super.bar(args)
        }
    }
    

    然后可以使用 Java 中的 vararg 语法调用 JavaFoo vararg 方法。

    希望对你有帮助:)

    【讨论】:

    • 嗯...尝试了 Daniel 的建议,但我无法使用 scala 2.8 beta 来实现它。对 java vararg 和 scala vararg 的编译是最近刚刚添加的吗?反编译字节码只会产生一个带有公共 void bar(Seq args) 方法的 Foo 类...
    【解决方案3】:

    answer to this question

    您可以使用@annotation.varargs 来指示scala 生成这两种方法:

    class Foo {
      @annotation.varargs def bar(args : String*) : Unit = println("Foo.bar with: " + args)
      def bar(args : Array[String]) : Unit = bar(args.toSeq : _*)
    }
    

    【讨论】:

      【解决方案4】:

      尽管有关于使用 Java 接口 强制 Scala 编译器“兼容”的有用提示,但我就是无法让我的代码工作。最终,我意识到这些方法是在 Scala object 上声明的,这意味着它们实际上是静态的,并且您不能在接口中指定静态方法,因此编译器基本上只是忽略了这样一个事实:对象实现了接口。对我来说幸运的是,有一个解决方法。而不是像这样直接从 Java 调用静态方法:

      CLASS.method(x,y,z)
      

      你必须这样称呼它:

      CLASS$.MODULE$.method(x,y,z)
      

      这意味着您实际上将单例对象作为静态字段引用的实例访问,并且由于它是一个实例,并且实现了java接口,那里编译器正确地完成了它的工作并实现了 varargs 方法,以便 Java 可以将其作为 varargs 调用。

      我个人认为这应该算是Scala编译器的bug。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-02
        • 2012-05-27
        相关资源
        最近更新 更多