與VAL

2015-04-30 41 views
-1

在Scala中,如果我們有一個類說斯卡拉Java的互操作性,與VAL

case class B(b: Int) 
object B { 
    def main(args: Array[String] { 
     val b = B(1) 
     b.b = 2 // ** compile time error here ** 
    } 
} 

會給出一個錯誤的說法,當scalac B.scala

error: reassignment to val 
b.b = 2 
    ^

一切編譯罰款是到這裏。

但是,如果我有一個Java類A.java

public class A { 
    public int a; 
    public A(int a) {this.a = a;} 
    public void setA(int a_) {this.a = a_;} 
    public String toString() {return "A: " + a;} 
} 

先用javac A.java編譯它, 然後在斯卡拉與val使用它:

object B { 
    def main(args: Array[String] { 
     val a = new A(1) 
     println("Before assignment: " + a) 
     a.a = 2 // ** No error here ** 
     println("After assignment: " + a) 
    } 
} 

編譯B.scalascalac B.scala與運行scala B。沒有錯誤發生。

它在scala中打破val的意向嗎?

如果我想在scala中使用java類時,維護實例a的固定值,我該怎麼辦?

或者實際上有一些文件提到這種行爲?

Environment: Scala version 2.11.5 (OpenJDK 64-Bit Server VM, Java 1.7.0_75). 
Centos 6.6 

編輯

謝謝大家對您的回覆。

雖然我很清楚,通過使字段最終: public final int a;,可以實現不變性。

我不希望通過修改java代碼來解決這個問題。 想象一下,我正在使用第三方Java庫,我無法修改他們的代碼,但我想確保我的代碼不會意外修改第三方的內部狀態,因此出現val

此外,通過使用javap -c拆卸.class文件,可以看出清楚,階不被插入到finalB使B.b不可改變的。

也許有人解釋背後val「神奇」將是您的Java類A有用

+0

您應該像這樣定義'b':'case class B(var b:Int)' –

回答

2

顯然,成員a是公衆和可變的。要將Java變量作爲Scala val處理,您可以在您的Java類中創建它final

另外請記住,斯卡拉也有var它具有與Java變量基本相同的行爲(除了final之一)。

編輯1

定義B像這樣:

case class B(val b: Int, var c: Int) 

再檢查編譯的類定義

$ javap B 
Compiled from "B.scala" 
public class B implements scala.Product,scala.Serializable { 
    public static scala.Option<scala.Tuple2<java.lang.Object, java.lang.Object>> unapply(B); 
    public static B apply(int, int); 
    public static void main(java.lang.String[]); 
    public int b(); 
    public int c(); 
    public int copy$default$1(); 
    public int copy$default$2(); 
    public void c_$eq(int); 
    public B copy(int, int); 
    public java.lang.String productPrefix(); 
    public int productArity(); 
    public java.lang.Object productElement(int); 
    public scala.collection.Iterator<java.lang.Object> productIterator(); 
    public boolean canEqual(java.lang.Object); 
    public int hashCode(); 
    public java.lang.String toString(); 
    public boolean equals(java.lang.Object); 
    public B(int, int); 
} 

一點需要注意的是,爲成員 'C' 你將有public void c_$eq(int);但成員b沒有這樣的方法。實際上在Scala中,這個任務最終變成了一個方法調用。

我希望能讓它更清晰。

+0

謝謝您的回覆。在scala中,我不必指定'B.b'的可訪問性。使用'val',編譯器會在重新分配'B.b = 2'時愉快地拋出錯誤。但是,使用java類時不能確保編譯時檢查。我想知道如果使用'val',是否有阻止我重新分配'a.a = 3'? – user2829759

+0

您定義了'val a = new A(1)',這很好。然而'a.a'不是scala的'val'。它實際上是Scala的一個'var'。爲了讓編譯器產生錯誤,你可以隱藏它'private A.a',或者使它成爲final'a'。 – tuxdna

+0

通過用'javap B.class -c'檢查'B.class',很明顯,編譯生成的所有東西都是'public'。那麼也許除了「公共/私人」以外還有其他的東西? – user2829759

0

您的困惑來自val a = new A(1)object B。這意味着你不能將價值重新分配給變量a,但完全可以重新分配a的任何字段。這可以通過標記日提交的最終

請嘗試在你的java類public int afinal如下

public class A { 
    public final int a; 
    public A(int a) {this.a = a;} 
    //public void setA(int a_) {this.a = a_;} //Compilation error here. Cannot assign to a final field 
    public String toString() {return "A: " + a;} 
} 

它會強制將現場A類的a不能重新分配的限制。