2011-10-02 18 views
5

io sono ancora abbastanza nuovo per Scala, ma so che è possibile definire variabili di classe che vengono inizializzate nel costruttore comeScala variabili finali costruttore

class AClass(aVal: String) 

che sarebbe come fare quanto segue in java

class AClass { 
    private String aVal; 

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

In Java, dichiarare aVal come finale. C'è un modo per rendere la variabile aVal finale nella sintassi di Scala?

EDIT: Ecco quello che sto vedendo quando compilo la seguente classe Scala:

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

mi sono imbattuto javap -private ed ho ottenuto l'uscita

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

Quando ho modificare la definizione di classe scala di avere class AClass(**val** aVal: String) Ottengo il seguente output da 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); 
} 

Viene generato il metodo pubblico aVal. Sto ancora imparando qui - qualcuno può spiegare perché viene generato?

Nota Sto usando Scala 2,9

risposta

10
class AClass(aVal: String) 

In questo codice, Aval è una variabile finale. Quindi hai già una variabile finale.

class AClass(val aVal: String) 

In questo codice, Aval è definitiva e si dispone di getter di Aval. Così si può utilizzare come qui di seguito

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

scala> a.aVal 
res2: String = aa 

E, infine,

class AClass(var aVal: String) 

In questo codice, Aval non è definitivo e si dispone di getter e setter di Aval. Così si può utilizzare come qui di seguito

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

copiato da mia risposta: Scala final vs val for concurrency visibility

ci sono due significati del termine final: a) per i campi Scala/metodi e metodi Java significa "non può essere overridded in una sottoclasse "eb" per i campi Java e nel bytecode JVM significa "il campo deve essere inizializzato nel costruttore e non può essere riassegnato".

I parametri di classe contrassegnati con val (o, equivalentemente, i parametri della classe del caso senza un modificatore) sono effettivamente definitivi nel secondo senso e quindi thread-safe.

Ecco la prova:

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, che può essere eseguito comodamente dal 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); 
} 

Se il parametro di classe di una classe non-caso non è contrassegnato come un val oppure var, e non è riferito a nessun metodo, deve solo essere visibile al costruttore della classe. Il compilatore Scala è quindi libero di ottimizzare il campo lontano dal bytecode. In Scala 2.9.1, sembra funzionare:

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. Devo aver dimenticato di ricompilare e quindi convalidare le mie scoperte con il comportamento delle implementazioni precedenti (http://scala-programming-language.1934581.n4.nabble.com/Val-and-Final-td1993410.html). Sei davvero corretto. Il problema che ho menzionato riguardo alle sottoclassi di essere in grado di sovrascrivere vals (e questo è un problema per le finali) è aggirato in virtù del fatto che il campo sottostante è privato e gli accessor nelle classi generate che sovrascrivono quelli del genitore (che non sono definitivi). Grazie per averlo impostato correttamente. – Chris

Problemi correlati