Как вы вызываете одноэлементный метод Scala из Java?
Я пытаюсь внедрить некоторый код Scala в мое существующее Java-приложение. (Так что, как говорится, я хочу больше веселья).
Я создаю синглтон в Scala
ScalaPower.scala
package org.fun
class ScalaPower
object ScalaPower{
def showMyPower(time:Int) = {
(0 to time-1).mkString(", ")
}
}
Теперь внутри OldJava.java
class OldJava {
public void demo(){
System.out.println(?)
}
}
Что я должен заполнить ?
чтобы Java вызывала метод showMyPower? Я пробовал оба org.fun.ScalaPower.showMyPower(10)
а также org.fun.ScalaPower.getInstance().showMyPower(10)
но никто не работает.
(Декомпилируйте файл класса, используя Jad, покажите мне только бессмысленный код.)
Изменить Я удаляю class ScalaPower
Объявление и Scala создают статический метод, как и ожидалось. (позвонить org.fun.ScalaPower.showMyPower(10)
просто работает).
Интересно, если это ошибка в компиляторе Scala или нет
5 ответов
Я думаю, что это косвенно охватывает это:
Сопутствующие объекты и статические методы Java
Есть еще одна вещь, которую нужно знать о сопутствующих объектах. Всякий раз, когда вы определяете основной метод для использования в качестве точки входа для приложения, Scala требует, чтобы вы поместили его в объект. Однако на момент написания этой статьи основные методы не могли быть определены в сопутствующем объекте. Из-за деталей реализации в сгенерированном коде JVM не найдет основной метод. Эта проблема может быть решена в будущем выпуске. На данный момент вы должны определить любой основной метод в одноэлементном объекте (то есть, объект "не в компаньоне") [ScalaTips]. Рассмотрим следующий пример простого класса Person и объекта-компаньона, который пытается определить main.
Как найдено здесь: http://programming-scala.labs.oreilly.com/ch06.html
Короче говоря, поскольку ваш объект является объектом-компаньоном (имеет класс-компаньон), вы не можете вызывать его так, как ожидаете. Как вы обнаружили, если вы избавитесь от класса, он будет работать.
Обычно лучше получить доступ к синглтону непосредственно из его собственного класса.
В этом случае:
org.fun.ScalaPower$.MODULE$.showMyPower(10);
Не вдаваясь в подробности реализации, Scala различает пространства имен между Object и Class/Trait. Это означает, что они могут использовать то же имя. Однако у объекта есть класс, и поэтому ему требуется искаженное имя в JVM. Текущие соглашения Scala заключаются в добавлении $ в конце имени модуля (для модулей верхнего уровня). Если объект определен в классе, я считаю, что соглашение - OuterClass$ModuleName$. Для реализации свойства singleton модуля ScalaPower есть также статический член MODULE$ класса ModuleName $. Это инициализируется во время загрузки класса, гарантируя, что существует только один экземпляр. Побочным эффектом этого является то, что вы не должны делать никакой блокировки в конструкторе модуля.
В любом случае, в Scala встроен механизм статического перенаправления "сделай вещи лучше для Java". Здесь он записывает статические методы для класса ScalaPower, которые просто вызывают ScalaPower$.MODULE$.someMethod(). Если вы также определите сопутствующий класс, сгенерированные серверы пересылки будут ограничены, так как вам не разрешено конфликтовать с именами со статическими методами и методами уровня экземпляра в JVM. Я думаю, что в 2.8.0 это означает, что если у вас есть объект-компаньон, вы потеряете свои статические пересылки.
В этом случае "наилучшей практикой" будет всегда использовать ссылку ScalaPower $.MODULE$ вместо статического перенаправителя, так как пересылка может исчезнуть с модификациями класса ScalaPower.
РЕДАКТИРОВАТЬ: опечатка
Какие ошибки вы получили? Используя ваш пример Scala и следующий класс Java:
cat test.java
:
import org.fun.*;
public class test {
public static void main(String args[]) {
System.out.println("show my power: " + ScalaPower.showMyPower(3));
}
}
И работает так:
java -cp .:<path-to/scala/install-dir>/lib/scala-library.jar test
дает мой вывод:
show my power: 0, 1, 2
Имейте в виду, что акции javap
инструмент можно использовать, чтобы увидеть, что производит компилятор Scala. Конечно, он не дает прямого ответа на ваш вопрос, но когда вам нужно просто напомнить о шаблонах генерации кода, этого достаточно.
После выполнения
class ScalaPower
object ScalaPower{
def showMyPower(time:Int) = {
(0 to time-1).mkString(", ")
}
}
ScalaPower.showMyPower(10)
работает как положено.