Scala主构造函数及其生成的字段/属性

时间:2017-03-18 17:29:56

标签: scala constructor

Scala的新功能,无论我阅读了多少篇文章/教程(如these | three | ones),我似乎无法围绕构造函数的工作方式。

我们来看一个主要构造函数的三个例子:

// 1
class Fizz(buzz : Buzz) { ... }

// 2
class Fizz (val buzz : Buzz) { ... }

// 3
class Fizz (var buzz : Buzz) { ... }

对于以下每一个:

  • 是否创建了buzz属性?
    • 如果是的话,是否公开?
    • 可变吗?
    • 是静态的吗?
    • 是否为它创建了一个getter / setter?
  • 是否创建了buzz字段?
    • 如果是的话,是否公开?
    • 可变吗?
    • 是静态的吗?
    • 是否为它创建了一个getter / setter?
  • 还有什么特别/值得注意的吗?

2 个答案:

答案 0 :(得分:4)

构造函数实际上是Scala中非常野蛮的野兽。事实上,Scala编译器能够为您做出一些明智的选择。

通过你的问题的措辞,我认为你可能有一些Java经验。为了清楚地说明发生了什么 - 并允许您在将来进行实验 - 让我们反编译Scala编译器生成的代码,以便我们可以看到Java等价物。为简明起见,我只会显示方法/字段的声明,而不是它们的实现。

没有限定符,buzz仅在构造函数

中使用
class Fizz(buzz : Buzz)

将编译为Java等效的

public class Fizz {
    public Fizz(Buzz);
}

由于Fizz没有声明引用buzz的任何方法/字段(除了构造函数本身),Scala不会为它创建任何字段/方法。

没有限定符,buzz在构造函数

之外引用
class Fizz(buzz : Buzz) {
    def foo: Buzz = buzz
}

buzz方法使用foo,因此编译器必须将其存储为字段。由于该字段未声明为var,因此会将其设为private final

public class Fizz {
  private final Buzz buzz;
  public Buzz foo();
  public Fizz(Buzz);
}

val限定符

class Fizz(val buzz : Buzz)

这一次,您明确表示您希望buzz成为val。这样可以创建一个private final字段来保存buzz,以及一个公共方法来访问它。

public class Fizz {
  private final Buzz buzz;
  public Buzz buzz();
  public Fizz(Buzz);
}

var限定符

class Fizz(var buzz : Buzz)

这种情况与前一种情况非常相似,只是现在您要指定您希望能够修改buzz。这将导致Scala编译器为您提供一个setter方法,名称为buzz_$eq。由于命名方法中存在JVM约束,因此只需要$ shenanigan。在Scala代码中,此方法将显示为buzz_=,语法糖将允许您将其称为fizz.buzz = someBuzz。这样,它实际上看起来好像你在变异为字段,但你实际上只是在调用一个setter。

public class Fizz {
  private Buzz buzz;
  public Buzz buzz();
  public void buzz_$eq(Buzz);
  public Fizz(Buzz);
}

如何反编译Scala?

在调查此类问题时,这些命令很有用:

scalac Fizz.scala

将创建一个不可读的编译Fizz.class。您可以使用

将其反编译为Java版本
javap -constants -p Fizz

在包含Fizz.class

的目录中

答案 1 :(得分:0)

在所有情况下,您显示的字段也是构造函数的参数。

声明为val或var的参数成为公共成员。如果你在构造函数中使用变量,它们将不会成为成员,如果你在类中使用它们,它们将是私有成员。

在第一种情况class Fizz(buzz : Buzz){}buzz参数是不可变的而不是成员(我假设您不在任何地方使用它)。

在第二种情况class Fizz (val buzz : Buzz) {}中,buzz参数是不可变的,并成为公共成员。

在第三种情况class Fizz (var buzz : Buzz) {}中,buzz参数是可变的并成为公共成员。

在所有情况下,并没有自动创建任何getter或setter。