2016-12-15 95 views
1

我在Scala REPL中運行簡單代碼,它創建了兩個類,其中一個值爲Int,值爲x。具體方法如下:默認構造函數的參數如何轉換爲字段?

scala> class C(x: Int){} 
defined class C 

scala> new C(100).x 
<console>:13: error: value x is not a member of C 
     new C(100).x 
       ^

scala> class D(val x: Int){} 
defined class D 

scala> new D(100).x 
res1: Int = 100 

我的理解是,對C類變量x將成爲一個可變變量(默認var)和d類不可變的變量。但是,我遇到了這個問題,其中x不是C的成員。

是怎麼回事?

回答

3

要研究此問題,我們可以反向工程請參閱「編譯器會做什麼?」 :)

爲此,我們與內容 class C(x: Int){}運行編譯類C.scala

scalac C.scala

此,產生C.class。 現在,我們可以使用java class disassembler javap來查看編譯器將生成的內容。

運行 javap -p C.class 會產生:

public class C { 
    public C(int); 
} 

如果我們用 class D(val x: Int){} 重複整個過程中,我們會產生:

public class D { 
    private final int x; 
    public int x(); 
    public D(int); 
} 

我們可以看到,不同的是,關鍵詞val告訴類創建一個getter方法。

回到您的假設,如果沒有val關鍵字,則類變量將被定義爲mutable:這是錯誤的。證明我們可以更深入一級地進行拆解。通過運行:

javap -p -v C.class

我們得到(很多其他的信息中)這個片段:

{ 
    public C(int); 
    descriptor: (I)V 
    flags: ACC_PUBLIC 
    Code: 
     stack=1, locals=2, args_size=2 
     0: aload_0 
     1: invokespecial #14     // Method java/lang/Object."<init>":()V 
     4: return 
     LocalVariableTable: 
     Start Length Slot Name Signature 
      0  5  0 this LC; 
      0  5  1  x I 
     LineNumberTable: 
     line 4: 0 
     line 2: 4 
    MethodParameters: 
     Name       Flags 
     x        final 
} 

,你可以清楚地看到,類變量x仍然宣佈爲final,因此,不可變。

1

屬性在Scala類可以具有以下修飾:

  • val使得屬性不可改變;它總是公衆 - 這是有道理的,因爲該值不能改變
  • var,使屬性易變和公共
  • 沒有修飾,使屬性可變的和私人

代碼示例:

// no modifier 
class A(x: Int) { 
    def print() = { 
    x += 1 // this i fine, it's mutable 
    println(x) 
    } 
} 

val a = new A(3) 
// a.x - compile error, it's private 


// var 
class A(var x: Int) { 
    def print() = { 
    x += 1 // this is fine, it's mutable 
    println(x) 
    } 
} 

    val a = new A(3) 
    a.x // you can do this since it's public (modifier var) 

// val 
class A(val x: Int) { 
    def print() = { 
    // x += 1 // can't do this, it's immutable 
    println(x) 
    } 
} 

val a = new A(3) 
a.x // you can do this since it's public (modifier val) 

有關構造函數和類的更多信息:http://joelabrahamsson.com/learning-scala-part-four-classes-and-constructors/

+2

第一段中的所有3個聲明都是錯誤的:'val'和'var'並不總是公開的,這只是默認值;沒有修飾符,你可能有也可能沒有一個字段(它取決於參數是否用在任何方法中),但它無論如何都是不可變的。 –

+0

我同意他們並不總是公開的;你可以使用'private'修改,但我認爲答案的重點仍然存在,在這種情況下,它們是默認公開的。雖然我可以編輯答案。我願意編輯建議。關於方法,我不確定我完全理解。當你使用像class A(val t:Int)和't'這樣的東西時,這個例子會是類的屬性/字段嗎? –

+0

當你有'class A(i:Int)'時,類'A'沒有'i'的字段。 'i'只是一個(不可變的)構造函數參數。當你有'class A(i:Int){def foo = i}'時,類'A'具有一個私有的不可變字段'i'。 –

相關問題