2011-10-02 11 views
5

sigo siendo bastante nuevo en Scala, pero sé que se pueden definir variables de clase que se inicializan en el constructor comoScala variables finales en el constructor

class AClass(aVal: String) 

lo que sería como hacer lo siguiente en java

class AClass { 
    private String aVal; 

    public AClass(String aVal) { 
     this.aVal = aVal; 
    } 
} 

En Java, declararía aVal como definitivo. ¿Hay alguna manera de hacer que la variable aVal sea definitiva en la sintaxis de Scala?

EDIT: Aquí es lo que estoy viendo cuando compilo la siguiente clase Scala:

class AClass(aVal: String) { 
    def printVal() { 
    println(aVal) 
    } 
} 

me encontré javap -private y tengo la salida

public class AClass extends java.lang.Object implements scala.ScalaObject{ 
    private final java.lang.String aVal; 
    public void printVal(); 
    public AClass(java.lang.String); 
} 

Cuando cambie la definición de clase Scala tener class AClass(**val** aVal: String) Obtengo la siguiente salida de javap -private

public class AClass extends java.lang.Object implements scala.ScalaObject{ 
    private final java.lang.String aVal; 
    public java.lang.String aVal(); 
    public void printVal(); 
    public AClass(java.lang.String); 
} 

Se genera el método público aVal. Todavía estoy aprendiendo aquí. ¿Alguien puede explicar por qué se genera eso?

Nota estoy usando Scala 2,9

Respuesta

10
class AClass(aVal: String) 

En este código, Aval es una variable final. Entonces ya tienes una variable final.

class AClass(val aVal: String) 

En este código, aVal es final y usted tiene getter de aVAl. Así que se puede usar, como a continuación

scala> val a= new AClass("aa") 
a: A1 = [email protected] 

scala> a.aVal 
res2: String = aa 

Y, por último,

class AClass(var aVal: String) 

En este código, Aval no es definitiva y tiene get y set de Aval. Así que se puede usar, como a continuación

scala> val a= new AClass("aa") 
a: AClass = [email protected] 

scala> a.aVal 
res3: String = aa 

scala> a.aVal = "bb" 
a.aVal: String = bb 

scala> a.aVal 
res4: String = bb 
8

Copiado mi respuesta: Scala final vs val for concurrency visibility

Hay dos significados del término final: a) para Scala campos/métodos y los métodos de Java que significa "no puede ser overridded en una subclase "yb) para campos Java y en bytecode JVM significa que" el campo debe inicializarse en el constructor y no puede reasignarse ".

Los parámetros de clase marcados con val (o, de forma equivalente, los parámetros de clase de caso sin un modificador) son definitivamente finales en segundo sentido, y por lo tanto son seguros para subprocesos.

Aquí está la prueba:

scala> class A(val a: Any); class B(final val b: Any); class C(var c: Any) 
defined class A 
defined class B 
defined class C 

scala> import java.lang.reflect._ 
import java.lang.reflect._ 

scala> def isFinal(cls: Class[_], fieldName: String) = { 
    | val f = cls.getDeclaredFields.find(_.getName == fieldName).get 
    | val mods = f.getModifiers 
    | Modifier.isFinal(mods) 
    | } 
isFinal: (cls: Class[_], fieldName: String)Boolean 

scala> isFinal(classOf[A], "a") 
res32: Boolean = true 

scala> isFinal(classOf[B], "b") 
res33: Boolean = true 

scala> isFinal(classOf[C], "c") 
res34: Boolean = false 

O con javap, que se puede ejecutar cómodamente desde el REPL:

scala> class A(val a: Any) 
defined class A 

scala> :javap -private A 
Compiled from "<console>" 
public class A extends java.lang.Object implements scala.ScalaObject{ 
    private final java.lang.Object a; 
    public java.lang.Object a(); 
    public A(java.lang.Object); 
} 

Si el parámetro clase de una clase no caso no está marcado como un val o var, y no se lo menciona por ningún método, solo necesita ser visible para el constructor de la clase. El compilador de Scala es libre de optimizar el campo fuera del bytecode. En Scala 2.9.1, esto parece funcionar:

scala> class A(a: Any) 
defined class A 

scala> :javap -private A 
Compiled from "<console>" 
public class A extends java.lang.Object implements scala.ScalaObject{ 
    public A(java.lang.Object); 
} 
+0

Ug. Debo haber olvidado volver a compilar y luego corrobore mis hallazgos con el comportamiento de las implementaciones anteriores (http://scala-programming-language.1934581.n4.nabble.com/Val-and-Final-td1993410.html). Usted es de hecho correcto. El problema que mencioné acerca de que las subclases pueden anular vals (y que esto es un problema para finales) se elude en virtud de que el campo subyacente es privado y los accessors en las clases generadas anulan las del padre (que no son definitivas). Gracias por establecerlo. – Chris

Cuestiones relacionadas