对于Scala来说,无论我读了多少篇文章/教程(比如这些 \\ 三 / 几个),我似乎都不知道构造函数是如何工作的。
让我们举三个主构造函数的例子如下:
// 1
class Fizz(buzz : Buzz) { ... }
// 2
class Fizz (val buzz : Buzz) { ... }
// 3
class Fizz (var buzz : Buzz) { ... }其中每一项:
buzz属性?
buzz字段吗?
发布于 2017-03-18 18:47:57
在Scala中,构造函数实际上是一种很棒的野兽。实际上,Scala编译器能够为您做出一些明智的选择。
根据您问题的措辞,我认为您可能有一些Java方面的经验。为了非常清楚地说明正在发生的事情--并允许您在未来进行试验--让我们对Scala编译器生成的代码进行反编译,这样我们就可以看到Java的等价物。为了简洁起见,我只展示方法/字段的声明,而不是它们的实现。
没有限定符,buzz只在构造函数中使用
class Fizz(buzz : Buzz)将编译成相当于
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编译器以有趣的名称buzz_$eq为您提供一个setter方法。仅由于命名方法中的$约束,才需要使用JVM。在Scala代码中,此方法将显示为buzz_=,而语法糖将允许您将其称为fizz.buzz = someBuzz。这样,你看起来就像在变场一样,但实际上你只是在叫一个策划者。
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的目录中
发布于 2017-03-18 17:42:43
在所有情况下,您显示的字段也是构造函数的参数。
声明为val或var的参数成为公共成员。如果在构造函数中使用变量,它们将不会成为成员,如果在类中使用它们,则它们将是私有成员。
在第一种情况下,class Fizz(buzz : Buzz){}参数是不可变的,不会成为成员(我假设您在任何地方都不使用它)。
在第二种情况下,class Fizz (val buzz : Buzz) {}的buzz参数是不可变的,并成为公共成员。
在第三种情况下,class Fizz (var buzz : Buzz) {}的buzz参数是可变的,并成为公共成员。
同样,在所有情况下,都没有自动创建的getter或setter。
https://stackoverflow.com/questions/42877572
复制相似问题