默认构造函数的参数如何变成字段?

时间:2016-12-15 12:31:47

标签: scala

我在Scala REPL中运行简单代码,创建两个具有单Intx的类。以下是:

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成员的问题。

怎么样?

2 个答案:

答案 0 :(得分:3)

要研究这个问题,我们可以进行逆向工程,看看“编译器会做什么?” :)

为此,我们正在使用内容编译类C.scala class C(x: Int){}运行:

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关键字,类变量将被定义为可变:这是错误的。为了证明我们可以更深入地进行拆解。通过运行:

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 :(得分: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/