2010-07-19 9 views
21

Ich versuche Scala-Code in meine bestehende Java-App zu injizieren. (Also, gesagt, ich will noch mehr Spaß).Wie rufen Sie eine Scala Singleton-Methode von Java?

ich eine Singleton Sachen in der Scala

ScalaPower.scala 

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

nun innerhalb OldJava.java

class OldJava { 
    public void demo(){ 
    System.out.println(?) 
    } 
} 

Was soll ich dazu einfach ? so dass Java die showMyPower Methode aufrufen wird? Ich versuchte sowohl org.fun.ScalaPower.showMyPower(10) und org.fun.ScalaPower.getInstance().showMyPower(10), aber keine Arbeit.

(Decompile die Klassendatei Jad zeigen mit mir nichts als Unsinn Code.)

bearbeiten Ich entferne die class ScalaPower Erklärung und scala produzieren die statische Methode wie erwartet. (Anruf an org.fun.ScalaPower.showMyPower(10) funktioniert einfach).

Frage mich, ob es einen Fehler in scala Compiler ist oder nicht

+1

Was ist 'org.fun.ScalaPower.showMyPower (10)'? – OscarRyz

+0

Autsch, mein Schlechter. Vergessen, den Namespace zu ändern. Die Frage wurde bereits aktualisiert. Vielen Dank. –

+1

Übrigens können Sie "0 bis zur Zeit" anstelle von "0 bis Zeit-1" schreiben. –

Antwort

9

Ich denke, das es indirekt umfasst:

Companion Objekte und Java Static Methoden

Es gibt eine weitere Sache über Begleiter Objekte zu kennen. Wenn Sie eine Hauptmethode definieren, die als Eintrag für eine Anwendung verwendet werden soll, müssen Sie in Scala in ein Objekt einfügen. Zum Zeitpunkt der Erstellung dieses Artikels können Hauptmethoden jedoch nicht in einem Companion-Objekt definiert werden. Aufgrund von Implementierungsdetails im generierten Code findet die JVM die Hauptmethode nicht. Dieses Problem kann in einer zukünftigen Version behoben werden. Fürs Erste, müssen Sie eine Hauptmethode in einem Singleton-Objekt definieren (d. H. Ein "Nicht-Companion" -Objekt) [ScalaTips]. Betrachten Sie das folgende Beispiel einer einfachen Personenklasse und eines begleitenden Objekts, das versucht, main zu definieren.

Wie hier gefunden: http://programming-scala.labs.oreilly.com/ch06.html

Kurz gesagt, weil Ihr Objekt ein Begleitobjekt ist (hat einen Begleiter Klasse) Sie können es nicht nennen, wie Sie es erwarten. Wie du herausgefunden hast, wenn du die Klasse loswirst, wird es funktionieren.

+2

Das stimmt nicht mehr. Irgendwo zwischen dem Zeitpunkt als das geschrieben wurde und als Scala 2.8 wurde veröffentlicht, die Weiterleitungscode-Generierungsmuster wurden behoben, um Hauptmethoden in Begleitern zu ermöglichen. –

+0

Oooh, ausgezeichnet. Das Buch deutete an, dass sie sich wünschte, dass es geändert würde, aber nicht für 2.8 (und sie hatten viel Vorfreude auf 2.8-Ness). Das sagte der ursprüngliche Fragesteller gibt seine Version nicht, und von seinem "Edit entferne ich die Klasse ScalaPower Deklaration und scala produzieren die statische Methode wie erwartet." Es klingt immer noch so, als wäre das das Problem gewesen. –

+0

Danke. Das erklärt meine Situation. Ich wechsle gerade zu scala 2.8. Verdammt, das Eclipse-Scala-Plugin ist immer noch beschissen. –

3

Beachten Sie, dass das Lager javap Werkzeug verwendet werden kann, um zu sehen, was der Scala-Compiler erzeugt. Es beantwortet natürlich nicht direkt Ihre Frage, aber wenn Sie nur an die Codegenerierungsmuster erinnert werden müssen, reicht das aus.

+0

Danke. Ich werde es versuchen, wenn ich wieder zu Hause bin. (Jetzt bei der Arbeit) –

10

Was waren die Fehler, die Sie bekommen haben? Ihre Scala Probe verwenden und die folgenden Java-Klasse:

cat test.java:


import org.fun.*; 

public class test { 
    public static void main(String args[]) { 
     System.out.println("show my power: " + ScalaPower.showMyPower(3));  
    } 
} 

Und es läuft wie folgt:

java -cp .:<path-to/scala/install-dir>/lib/scala-library.jar test

gibt meine die Ausgabe:

show my power: 0, 1, 2

+1

Hmm, es ist komisch. Mein Code wird nicht einmal kompiliert. Es heißt '' Symbol 'showMyPower' nicht gefunden ''(obwohl IDEA Scala Plugin es verstehen und mir eine automatische Vervollständigung anbieten) –

+0

Ich finde heraus, dass die Methode' showMyPower' eigentlich in Scala $ deklariert ist, nicht in Scala. Welche Version von Scala verwenden Sie, die diesen Code kompilierbar macht? Ich benutze 2.7.5 –

+0

Ouch, 'org.fun.ScalaPower $ .MODULE $ .showMyPower' ist in der Tat die richtige Methode, die ich nennen sollte, Was zum Teufel? –

1

Nach

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

ScalaPower.showMyPower(10) funktioniert.

14

Es ist normalerweise besser, den Singleton direkt von seiner eigenen Klasse zu erreichen.

In diesem Fall:

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

Ohne zu sehr in die Details der Implementierung geht, unterscheidet Scala Namensraum zwischen Objekt und Klasse/Trait. Dies bedeutet, dass sie denselben Namen verwenden können. Ein Objekt hat jedoch eine Klasse und benötigt daher einen verfälschten Namen in der JVM. Die aktuellen Scala-Konventionen sind das Hinzufügen eines $ am Ende des Modulnamens (für Top-Level-Module). Wenn das Objekt in einer Klasse definiert ist, glaube ich, dass die Konvention OuterClass $ ModuleName $ ist. Um die Singleton-Eigenschaft des ScalaPower-Moduls zu erzwingen, gibt es auch ein statisches MODULE $ -Mitglied der ModulName $ -Klasse. Dies wird beim Laden der Klasse initialisiert, um sicherzustellen, dass es nur eine Instanz gibt. Ein Nebeneffekt davon ist, dass Sie nicht irgendeine Art von Sperren im Konstruktor eines Moduls tun sollten.

In jedem Fall hat Scala auch einen "make things netter for Java" -Static-Forwarder-Mechanismus eingebaut. Hier werden statische Methoden für die ScalaPower-Klasse geschrieben, die ScalaPower $ .MODULE $ .someMethod() aufrufen. Wenn Sie auch eine Companion-Klasse definieren, sind die Weiterleitungen, die generiert werden können, eingeschränkt, da Namenskonflikte mit statischen Methoden und Methoden auf Instanzebene in der JVM nicht zulässig sind. Ich denke, in 2.8.0 bedeutet das, wenn Sie ein Companion-Objekt haben, verlieren Sie Ihre statischen Forwarder.

In diesem Fall wäre es eine "bewährte Methode", immer die ScalaPower $ .MODULE $ -Referenz anstelle einer statischen Weiterleitung zu verwenden, da die Weiterleitung mit Änderungen an der ScalaPower-Klasse verschwinden könnte.

EDIT: Typo

+0

Der Code hier hat einen Tippfehler in MODUL $ –