2012-06-05 17 views
11

Vorrei creare una classe Java che segua la convenzione di setters/getter di Scala.Getter e setter Scala in classe Java

ho cercato seguente semplice classe, ma non funziona:

public class JavaA { 
private int a = 0; 

public int a() { 
    return a; 
} 

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

Ma quando cerco di accedervi da Scala:

val x = new JavaA 
x.a = 1 

ed ottengo il messaggio di errore "riassegnazione a val" . Ho provato a cercarlo, ma tutti i problemi che ho trovato erano il contrario da scala a java.

Qual è il modo giusto per farlo?

Grazie!

+0

Sto lavorando molto con EMF (model2model, model2text transformation) quindi ho pensato di rendere il codice un po 'più elegante con feature = value invece di setFeatute (valore). – fikovnik

risposta

13

Puoi solo fare questo, ed è già abbastanza difficile che tu non voglia.

Quello che non è possibile do è scrivere una classe Java nuda che magicamente viene interpretata come getter e setter Scala. La ragione è che Scala incorpora le informazioni nel file di classe che richiede per i suoi getter e setter (ad esempio ci sono zero blocchi di parametri o un blocco di parametri vuoto - una distinzione che non è conservata sulla JVM (o in Java)).

Cosa si può fare è utilizzare Java per implementare un'interfaccia Scala definita (es tratto):

// 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; } 
} 

Quello che non si può fare, anche così, è utilizzare direttamente la classe (ancora una volta perché Java non aggiunge le informazioni appropriate annotazioni per Scala):

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

ma dal momento che non implementare il tratto di successo LY, si può utilizzare, se lo desideri quando viene digitato come il tratto:

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

Quindi è piuttosto un miscuglio. Non è perfetto in alcun modo, ma in alcuni casi potrebbe essere abbastanza funzionale da dare una mano.

(L'altra alternativa, naturalmente, è quello di fornire una conversione implicita dalla classe Java per uno che ha un getter/setter che fa riferimento i metodi reali sulla classe Java; questo funziona anche quando non si può avere la Java ereditare da Scala)

(Edit:. Naturalmente non c'è ragione fondamentale che il compilatore deve agire in questo modo, si potrebbe sostenere che l'interpretazione Java-definiti coppie getter/setter come se fossero quelli Scala (cioè se il file di classe non dice esplicitamente che è di Scala) è un buon candidato per un miglioramento delle funzionalità per migliorare l'interoperabilità Java.

+0

Grazie per l'intuizione! Ero preoccupato che non funzionasse. – fikovnik

+0

Nizza; bel trucco con il tratto implementato! –

1

Ho paura che non puoi. In Scala, l'accessor deve essere un metodo senza lista parametri, come def a = _a. Scrivendo per es. def a() = _a in Scala causerebbe lo stesso errore e non è possibile definire un metodo senza elenco parametri in Java. Potresti essere in grado di ingannare il compilatore Scala generando il tuo ScalaSignature, ma probabilmente non ne vale la pena ...

+1

Il problema non è l'accessor, però. 'println (x.a)' funziona bene (come 'x.a _ = (1)'). –

+1

@TravisBrown Lo è perché lo zucchero sintattico funziona solo se esiste un tale accessorio, secondo le specifiche della lingua. –

+0

Ah! Hai ragione. Che strano. –