2016-12-15 93 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'。 –

相关问题