抽象方法和varargs注释

时间:2014-11-21 00:51:20

标签: java scala variadic-functions scala-java-interop

Scala提供了一个生成Java varargs转发器方法的@varargs annotation,可以编写如下内容:

import scala.annotation.varargs

class Foo {
  @varargs def foo(args: String*): Unit = {
    args.foreach(println)
  }
}

然后从Java调用此方法而无需创建scala.Seq

Foo foo = new Foo();
foo.foo("a", "b");

这很不错。

不幸的是,当方法是抽象的时,转发部分似乎不会发生:

trait Bar {
  @varargs def bar(args: String*): Unit
}

class Baz extends Bar {
  def bar(args: String*): Unit = {
    args.foreach(println)
  }
}

现在,如果我们有这个Java代码:

Bar bar = new Baz();
bar.bar("a", "b");

我们得到此异常(在运行时):

java.lang.AbstractMethodError: Baz.bar([Ljava/lang/String;)V

我们可以使用javap确认问题:

public interface Bar {
  public abstract void bar(java.lang.String...);
  public abstract void bar(scala.collection.Seq<java.lang.String>);
}

public class Baz implements Bar {
  public void bar(scala.collection.Seq<java.lang.String>);
  public Baz();
}

所以不,转发商肯定没有实施。

在两个bar方法上放置注释无法编译:

A method with a varargs annotation produces a forwarder method with the same
signature (args: Array[String])Unit as an existing method.

当然,只将注释放在bar Baz中,这意味着我们无法使用Bar实例中的转发器。

这似乎一定是个bug,但它似乎也很容易碰到,而且我在问题跟踪器中没有看到任何内容。我正确使用@varargs吗?如果是这样,是否有一种解决方法可以使它达到您期望的效果?

2 个答案:

答案 0 :(得分:2)

我不知道Scala,但在Java中,varargs只是一个数组。

所以在Java中它会以这种方式工作,只有一个警告:

package tests.StackOverflow.q27052394;

import java.util.Arrays;

public class Runner {

    public interface Bar {
      public abstract void bar(java.lang.String ... ss);
    }

    public static class Baz implements Bar {
      public void bar(java.lang.String[] array) {
          System.out.println(Arrays.toString(array));
      }
    }

    public static void main(String[] args) {

        Bar b = new Baz();

        b.bar("hello", "world");

    }

}

如果你能以同样的方式欺骗​​Scala,你可能会克服这个错误。

答案 1 :(得分:1)

实现目标的一种方法是在Java中定义接口,如下所示

interface Bar {
  public void bar(String... args);
}

然后通常在Scala中定义实现,如下所示

class Baz extends Bar {
  def bar(args: String*): Unit = {
    args.foreach(println)
  }
}

Scala编译器将认识到它需要生成vargs样式方法,并将生成varargs和Seq实现。

javap输出正如您所期望的那样

public class Baz implements Bar {
  public void bar(scala.collection.Seq<java.lang.String>);
  public void bar(java.lang.String[]);
  public Baz();
}

interface Bar {
  public abstract void bar(java.lang.String...);
}