Как вы вызываете одноэлементный метод 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 или нет?


person Phương Nguyễn    schedule 19.07.2010    source источник
comment
А как насчет org.fun.ScalaPower.showMyPower(10) ?   -  person OscarRyz    schedule 19.07.2010
comment
Ой, мой плохой. Забыл изменить пространство имен. Обновил вопрос уже. Спасибо.   -  person Phương Nguyễn    schedule 20.07.2010
comment
Кстати, вместо 0 to time-1 можно написать 0 until time.   -  person Jean-Philippe Pellet    schedule 10.02.2011


Ответы (5)


Я думаю, что это косвенно охватывает это:

Сопутствующие объекты и статические методы Java

Есть еще одна вещь, которую нужно знать о сопутствующих объектах. Всякий раз, когда вы определяете метод main для использования в качестве точки входа в приложение, Scala требует, чтобы вы поместили его в объект. Однако на момент написания этой статьи основные методы не могли быть определены в объекте-компаньоне. Из-за деталей реализации в сгенерированном коде JVM не найдет основной метод. Эта проблема может быть решена в будущем выпуске. На данный момент вы должны определить любой основной метод в объекте-одиночке (т. е. объекте, не являющемся компаньоном) [ScalaTips]. Рассмотрим следующий пример простого класса Person и объекта-компаньона, который пытается определить main.

Как здесь: http://programming-scala.labs.oreilly.com/ch06.html

Короче говоря, поскольку ваш объект является сопутствующим объектом (имеет сопутствующий класс), вы не можете называть его так, как ожидаете. Как вы обнаружили, если вы избавитесь от класса, он будет работать.

person Ry4an Brase    schedule 20.07.2010
comment
Это уже не так. Где-то между тем, когда это было написано, и когда был выпущен Scala 2.8, шаблоны генерации кода пересылки были исправлены, чтобы разрешить основные методы в компаньонах. - person Randall Schulz; 20.07.2010
comment
Ооо, отлично. В книге намекнули, что они хотели бы, чтобы она была изменена, но ничего не сказано о версии 2.8 (и они с нетерпением ждали версии 2.8). Тем не менее, исходный вопросник не дает свою версию, и из его редактирования я удаляю объявление класса ScalaPower, и scala создает статический метод, как и ожидалось. все еще кажется, что это могло быть проблемой. - person Ry4an Brase; 20.07.2010
comment
Спасибо. Это объясняет мою ситуацию. Я перехожу на scala 2.8 прямо сейчас. Черт, плагин eclipse scala все еще отстой. - person Phương Nguyễn; 20.07.2010
comment
у нас здесь неработающая ссылка - person WarFox; 22.01.2014

Обычно лучше обращаться к синглтону напрямую из его собственного класса.

В таком случае:

org.fun.ScalaPower$.MODULE$.showMyPower(10);

Не вдаваясь в подробности реализации, Scala различает пространства имен между Object и Class/Trait. Это означает, что они могут использовать одно и то же имя. Однако у объекта есть класс, и поэтому ему нужно искаженное имя в JVM. Текущие соглашения Scala заключаются в добавлении $ в конце имени модуля (для модулей верхнего уровня). Если объект определен в классе, я полагаю, что используется соглашение OuterClass$ModuleName$. Чтобы реализовать одноэлементное свойство модуля ScalaPower, существует также статический член MODULE$ класса ModuleName$. Это инициализируется во время загрузки класса, гарантируя, что существует только один экземпляр. Побочным эффектом этого является то, что вы не должны не выполнять какую-либо блокировку в конструкторе модуля.

В любом случае, Scala также встроила в него механизм статической пересылки "улучшить ситуацию для Java". Здесь он пишет статические методы класса ScalaPower, которые просто вызывают ScalaPower$.MODULE$.someMethod(). Если вы также определяете класс-компаньон, количество пересылателей, которые могут быть сгенерированы, ограничено, поскольку вам не разрешено иметь конфликты имен со статическими методами и методами уровня экземпляра в JVM. Я думаю, что в версии 2.8.0 это означает, что если у вас есть объект-компаньон, вы теряете свои статические серверы пересылки.

В этом случае "лучшей практикой" было бы всегда использовать ссылку ScalaPower$.MODULE$ вместо статического сервера пересылки, так как сервер пересылки может исчезнуть при изменении класса ScalaPower.

РЕДАКТИРОВАТЬ: опечатка

person jsuereth    schedule 10.08.2010

Какие ошибки вы получали? Используя ваш образец 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

person Arjan Blokzijl    schedule 19.07.2010
comment
Хм, это странно. Мой код даже не компилируется. Он говорит "Symbol 'showMyPower' not found" (хотя плагин IDEA Scala это понимает и предлагает мне автодополнение) - person Phương Nguyễn; 20.07.2010
comment
Я обнаружил, что на самом деле метод showMyPower объявлен внутри Scala$, а не Scala. Какую версию Scala вы используете, чтобы сделать этот код компилируемым? Я использую 2.7.5 - person Phương Nguyễn; 20.07.2010
comment
Ой, org.fun.ScalaPower$.MODULE$.showMyPower действительно правильный метод, который я должен вызывать. Какого черта? - person Phương Nguyễn; 20.07.2010
comment
Черт возьми, я удалил объявление class ScalaPower перед object ScalaPower, и оно скомпилировалось так, как вы говорили. - person Phương Nguyễn; 20.07.2010
comment
Я использую Scala 2.8.0 final, не могли бы вы попробовать и эту версию? Существует два класса Generetad: ScalaPower и ScalaPower$ (последний с полем MODULE$, как вы описали). ScalaPower имеет метод public static final java.lang.String showMyPower(int); который я мог бы назвать, как описано выше. - person Arjan Blokzijl; 21.07.2010

Имейте в виду, что стандартный инструмент javap можно использовать для просмотра того, что производит компилятор Scala. Конечно, это не дает прямого ответа на ваш вопрос, но когда вам нужно просто напомнить о шаблонах генерации кода, этого достаточно.

person Randall Schulz    schedule 19.07.2010

После выполнения

class ScalaPower 
object ScalaPower{
  def showMyPower(time:Int) = {
    (0 to time-1).mkString(", ")
  }
}

ScalaPower.showMyPower(10) работает как положено.

person Jus12    schedule 09.08.2010