Как вы вызываете одноэлементный метод 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) работает как положено.

Другие вопросы по тегам