2011-10-02 76 views
5

斯卡拉最終變量我還是很新的斯卡拉,但我知道你可以定義在Java在構造

以下是在構造像

class AClass(aVal: String) 

初始化類變量這將是像做

class AClass { 
    private String aVal; 

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

在Java中,我會聲明aval作爲final。有沒有辦法讓Scala語法中的aVal變量最終成爲可能?

編輯:這是當我編譯下面的斯卡拉類我所看到的:

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

我跑javap -private並得到了輸出

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

當我改變了Scala的類定義有class AClass(**val** aVal: String)我從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); 
} 

生成公共方法aVal。我仍然在這裏學習 - 任何人都可以解釋爲什麼產生?

注意我使用Scala的2.9

回答

10
class AClass(aVal: String) 

在這段代碼中,票據背書擔保是最終的變數。所以你已經有了一個最終的變量。

class AClass(val aVal: String) 

在這段代碼中,aVal是final的,你有aVAl的getter。所以,你可以使用它像下面

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

scala> a.aVal 
res2: String = aa 

最後,

class AClass(var aVal: String) 

在這段代碼中,票據背書擔保是不是最終版本,你有getter和票據背書擔保的制定者。所以,你可以使用它像下面

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

從我的答案複製:Scala final vs val for concurrency visibility

有術語final的兩層含義:一)斯卡拉字段/方法和Java方法它的意思是「不能被overridded子類「和b)用於Java字段,而在JVM字節碼中則意味着」該字段必須在構造函數中初始化並且不能被重新分配「。

標記爲val(或者等價地,沒有修飾符的案例類參數)的類參數在第二意義上確實是最終的,因此線程安全。

這裏的證明:

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 

或者與javap,可以從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); 
} 

如果不區分類的類參數沒有被標記爲valvar,並且它不是從任何方法引用的,它只需要對類的構造函數可見。然後Scala編譯器可以自由地優化遠離字節碼的字段。在斯卡拉2.9.1,這似乎工作:

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。我一定忘了重新編譯,然後用舊版本的行爲來證實我的發現(http://scala-programming-language.1934581.n4.nabble.com/Val-and-Final-td1993410.html)。你確實是對的。我提到的有關子類能夠覆蓋vals的問題(這是一個問題)是由於隱藏的字段是私有的,並且生成的類中的訪問器覆蓋父類中的訪問器(這不是最終的)。感謝您設置它。 – Chris