2012-06-05 8 views
11

Ich möchte eine Java-Klasse erstellen, die die Scala Setter/Getter Konvention folgt.Scala Getter und Setter in Java-Klasse

habe ich versucht, einfach Klasse folgen, aber es funktioniert nicht:

public class JavaA { 
private int a = 0; 

public int a() { 
    return a; 
} 

public void a_$eq(int a) { 
    this.a = a; 
} 
} 

Aber wenn ich versuche, es von scala zuzugreifen:

val x = new JavaA 
x.a = 1 

und ich „Neuzuordnung val“ Fehlermeldung . Ich habe versucht, danach zu suchen, aber alle Probleme, die ich gefunden habe, wo umgekehrt scala zu java.

Was ist der richtige Weg?

Danke!

+0

Ich arbeite viel mit EMF (model2model, model2text transformation), also dachte ich, ich werde den Code etwas eleganter machen mit feature = value anstelle von setFeatute (value). – fikovnik

Antwort

13

Sie können nur Art, dies zu tun, und es ist schwer genug, dass Sie wahrscheinlich nicht wollen.

Was Sie kann nicht Do ist eine nackte Java-Klasse schreiben, die magisch als Scala Getter und Setter interpretiert wird. Der Grund ist, dass Scala Informationen in die Klassendatei einbettet, die sie für ihre Getter und Setter benötigt (z. B. gibt es Null-Parameterblöcke oder einen leeren Parameterblock - eine Unterscheidung, die auf der JVM (oder in Java) nicht beibehalten wird).

Was Sie können tun, ist Java verwenden, um eine Scala-definierte Schnittstelle (zB Merkmal) zu implementieren:

// GetSetA.scala 
trait GetSetA { def a: Int; def a_=(a: Int): Unit } 

// JavaUsesGSA.java 
public class JavaUsesGSA implements GetSetA { 
    private int a = 0; 
    public int a() { return a; } 
    public void a_$eq(int a) { this.a = a; } 
} 

Was Sie nicht tun, auch so, ist direkt die Klasse verwenden (wieder da Java die entsprechenden Kommentarinformationen für Scala) nicht hinzufügen:

scala> j.a = 5 
<console>:8: error: reassignment to val 
     j.a = 5 

aber da es das Merkmal erfolgreich nicht implementiert ly, können Sie es wie gewünscht verwenden, wenn es als das Merkmal eingegeben wird:

scala> (j: GetSetA).a = 5 
(j: GetSetA).a: Int = 5 

es ist also eher eine bunte Mischung. Nicht perfekt auf jeden Fall, aber es kann ausreichend funktionell sein, um in einigen Fällen zu helfen. Die andere Alternative besteht natürlich darin, eine implizite Konvertierung von der Java-Klasse zu einer zu liefern, die einen Getter/Setter hat, der auf die realen Methoden der Java-Klasse verweist; dies funktioniert auch dann, wenn Sie nicht über die Java-Klasse verfügen Java erbt von Scala)

(Edit:. natürlich gibt es keinen kritischen Grund ist, dass der Compiler muss so handeln, man könnte argumentieren, dass Java-definiert Getter/Setter-Paare zu interpretieren, als ob sie Scala diejenigen waren (dh, wenn Die Klassendatei sagt nicht explizit, dass es von Scala stammt.) ist ein guter Kandidat für eine Funktionserweiterung, um die Java-Interoperabilität zu verbessern.)

+0

Danke für die Einsicht! Ich habe mir Sorgen gemacht, dass es nicht funktioniert. – fikovnik

+0

Nizza; cooler Trick mit dem eingeführten Merkmal! –

1

Ich fürchte, Sie können nicht. In Scala muss der Accessor eine Methode ohne Parameterliste sein, wie def a = _a. Schreiben z.B. def a() = _a in Scala würde den gleichen Fehler verursachen, und es gibt keine Möglichkeit, dass Sie eine Methode ohne Parameterliste in Java definieren können. Sie können Ihren eigenen durch Erzeugen ScalaSignature die Scala-Compiler täuschen können, aber das ist wahrscheinlich nicht der Mühe wert ...

+1

Das Problem ist jedoch nicht der Accessor. 'println (x.a)' funktioniert genauso gut (wie 'x.a _ = (1)'). –

+1

@TravisBrown Es ist, weil der syntaktische Zucker nur funktioniert, wenn es einen solchen Accessor gibt, gemäß der Sprachspezifikation. –

+0

Ah! Du hast recht. Wie seltsam. –