2012-06-05 13 views
11

Me gustaría crear una clase Java que siga la convención Scala setters/getters.Scala getters y setters en la clase Java

me trataron siguiente clase simple, pero no funciona:

public class JavaA { 
private int a = 0; 

public int a() { 
    return a; 
} 

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

Pero cuando trato de acceder a él desde Scala:

val x = new JavaA 
x.a = 1 

y me sale el mensaje de error "reasignación a val" . Traté de buscar esto, pero todos los problemas que encontré fueron al revés de scala a java.

¿Cuál es la forma correcta de hacerlo?

Gracias!

+0

Estoy trabajando mucho con EMF (model2model, model2text transformation) así que pensé en hacer el código un poco más elegante con feature = value en lugar de setFeatute (value). – fikovnik

Respuesta

13

Solo puede hacer esto, y es suficientemente difícil que probablemente no quiera.

Lo que no se puede hacer es escribir una clase de Java desnuda que mágicamente se interpreta como getters y setters Scala. La razón es que Scala incorpora información en el archivo de clase que requiere para sus getters y setters (por ejemplo, hay cero bloques de parámetros o un bloque de parámetros vacío, una distinción que no se conserva en la JVM (o en Java)).

Lo que puede hacer es utilizar Java para implementar una interfaz definida Scala (es decir rasgo):

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

Lo que no se puede hacer, aún así, es utilizar la clase directamente (otra vez porque Java no añadir la información de anotación apropiada para Scala):

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

pero ya que no implementar con éxito el rasgo Ly, se puede utilizar según se desee cuando se escribe como el rasgo:

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

Por lo tanto, es más bien una mezcla de cosas. No es perfecto de ninguna manera, pero puede ser lo suficientemente funcional como para ayudar en algunos casos.

(La otra alternativa, por supuesto, es proporcionar una conversión implícita de la clase Java a una que tenga un getter/setter que haga referencia a los métodos reales en la clase Java; esto funciona incluso cuando no se puede java heredar de Scala)

(Edit:. Por supuesto, no hay ninguna razón fundamental que el compilador debe actuar de esta manera, se podría argumentar que la interpretación de pares de captador/definidor definidas en Java como si fueran los Scala (es decir, si el archivo de clase no dice explícitamente que es de Scala) es un buen candidato para una mejora de características para mejorar la interoperabilidad de Java.)

+0

¡Gracias por la información! Estaba preocupado de que no funcione. – fikovnik

+0

Agradable; buen truco con el rasgo implementado! –

1

Me temo que no puedes. En Scala, el acceso debe ser un método sin lista de parámetros, como def a = _a. Escribiendo, por ejemplo def a() = _a en Scala causaría el mismo error, y no hay forma de que pueda definir un método sin lista de parámetros en Java. Puede engañar al compilador de Scala generando su propio ScalaSignature, pero eso probablemente no valga la pena ...

+1

El problema no es el acceso, sin embargo. 'println (x.a)' funciona bien (al igual que 'x.a _ = (1)'). –

+1

@TravisBrown Lo es, porque el azúcar sintáctico solo funciona si existe tal accesorio, según las especificaciones del lenguaje. –

+0

¡Ah! Tienes razón. Que raro. –

Cuestiones relacionadas