Как объявить метод scala, чтобы его можно было вызвать из Java, используя стиль varargs
У меня есть 2 простых метода в классе библиотеки scala:
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, используя Java varargs-подобный синтаксис?
4 ответа:
В 2.8 (не знаю о 2.7), если вы переопределяете метод varargs из родительского Java или реализуете метод varargs из интерфейса Java, то компилятор Scala создаст два метода, один для Scala, другой для Java. Java-как вы можете убедиться сами, изучив байт-код-просто берет массив varargs и обертывает его, а затем передает WrappedArray в версию Scala, которая ожидает Seq.
Если есть способ заставить компилятор сгенерировать форвардер под других обстоятельств я не знаю. Я сомневаюсь, что он существует. Похоже, что предоставление способа попросить его (аннотацию, я думаю) было бы разумным запросом на улучшение.
Не совсем уверен, но я думаю, что varargs в Scala использует последовательности и отличается от реализации java. Я думаю, что самый простой способ выполнить то, что вы хотите, - это подкласс класса Foo scala в Java и добавить метод bar, который принимает Java vararg, т. е.
public class JavaFoo extends Foo { public void bar(String... args) { super.bar(args) } }
Метод JavaFoo количеством аргументов можно назвать, используя синтаксис с переменным числом аргументов в Java.
Надеюсь, это поможет :)
Смотрите ответ на этот вопрос :
Вы можете использовать
@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 : _*) }
Несмотря на полезную подсказку об использовании интерфейса Java , чтобы заставить компилятор Scala быть "совместимым", я просто не мог заставить мой код работать. В конце концов до меня дошло, что методы были объявлены на Scala object , что означает, что они фактически статичны, и вы не можете указать статические методы в интерфейсе, поэтому компилятор в основном просто игнорировал тот факт, что объект реализовал интерфейс. К счастью для меня, есть обходной путь. Вместо того, чтобы позвонить в статический метод непосредственно из Java, как это:
CLASS.method(x,y,z)
Вы должны назвать это так:
CLASS$.MODULE$.method(x,y,z)
Это означает, что вы фактически обращаетесь к объектуsingleton как к экземпляру, на который ссылается статическое поле, и поскольку это экземпляр и реализует интерфейс java, там компилятор выполняет свою работу должным образом и реализует метод varargs, так что Java может вызвать его как varargs.
Лично я считаю, что это следует рассматривать как ошибку компилятора Scala.