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
吗?如果是这样,是否有一种解决方法可以使它达到您期望的效果?
答案 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...);
}