2014-11-21 3 views
13

Scala обеспечивает @varargs annotation, который генерирует Java списков параметров метода форвардер, что позволяет написать что-то вроде этого:Абстрактные методы и переменные аргументы аннотацию

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 экземпляра.

Кажется, что это ошибка, но это также кажется чрезвычайно простым в использовании, и я не вижу ничего в трекер-проблеме. Я правильно использую @varargs? Если это так, есть ли обходной путь, который заставит его делать то, что вы ожидаете здесь?

+0

Oops. Кажется мне еще одна ошибка.Благодаря друг другу решение 'jugaad' для взаимодействия. Гоша! сколько еще там лежит? – Jatin

+0

Похоже на ошибку. Попробуйте представить новую ошибку для своего трекера. – Luminous

ответ

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 таким же образом, вы преодолеете ошибку.

+0

Добавление метода 'def bar (args: Array [String]): Unit = bar (args: _ *)' to 'Baz' на самом деле работает (хотя это не очень приятно). –

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...); 
} 
Смежные вопросы