Scala 新手,无论我读了多少文章/教程(比如这些|三个|),我似乎都无法理解构造函数是如何工作的。
让我们在这里举三个主构造函数的例子:
// 1
class Fizz(buzz : Buzz) { ... }
// 2
class Fizz (val buzz : Buzz) { ... }
// 3
class Fizz (var buzz : Buzz) { ... }
Run Code Online (Sandbox Code Playgroud)
对于其中每一个:
buzz创建了财产?
buzz创建了字段?
构造函数实际上是 Scala 中的一头野兽。事实上,Scala 编译器能够为您做出一些明智的选择。
从你的问题的措辞来看,我认为你可能对 Java 有一定的经验。为了完全清楚发生了什么 - 并允许您将来进行实验 - 让我们反编译 Scala 编译器生成的代码,以便我们可以看到 Java 的等效代码。为了简洁起见,我将仅显示方法/字段的声明,而不显示它们的实现。
buzz仅在构造函数中使用class Fizz(buzz : Buzz)
Run Code Online (Sandbox Code Playgroud)
将编译为 Java 等效项
public class Fizz {
public Fizz(Buzz);
}
Run Code Online (Sandbox Code Playgroud)
由于Fizz没有声明任何方法/字段引用buzz(除了构造函数本身),Scala 不会为其创建任何字段/方法。
buzz在构造函数外部引用class Fizz(buzz : Buzz) {
def foo: Buzz = buzz
}
Run Code Online (Sandbox Code Playgroud)
这次buzz由方法使用foo,因此编译器必须将其存储为字段。由于该字段未声明为 a var,因此将进行创建private final。
public class Fizz {
private final Buzz buzz;
public Buzz foo();
public Fizz(Buzz);
}
Run Code Online (Sandbox Code Playgroud)
val预选赛class Fizz(val buzz : Buzz)
Run Code Online (Sandbox Code Playgroud)
这一次,你明确表示你想buzz成为一名val。private final这将产生创建一个用于保存的字段buzz以及一个用于访问它的公共方法的效果。
public class Fizz {
private final Buzz buzz;
public Buzz buzz();
public Fizz(Buzz);
}
Run Code Online (Sandbox Code Playgroud)
var预选赛class Fizz(var buzz : Buzz)
Run Code Online (Sandbox Code Playgroud)
这种情况与前一种情况非常相似,只不过现在您指定您希望能够修改buzz. 这将导致 Scala 编译器为您提供一个 setter 方法,其有趣的名称为buzz_$eq. 之所以需要这个$恶作剧,只是因为 JVM 在命名方法方面有限制。在您的 Scala 代码中,此方法将显示为buzz_=,语法糖将允许您将其称为fizz.buzz = someBuzz。这样,它实际上看起来好像您正在作为字段进行变异,但实际上您只是调用了 setter。
public class Fizz {
private Buzz buzz;
public Buzz buzz();
public void buzz_$eq(Buzz);
public Fizz(Buzz);
}
Run Code Online (Sandbox Code Playgroud)
这些命令在调查此类问题时很有帮助:
scalac Fizz.scala
Run Code Online (Sandbox Code Playgroud)
将创建一个Fizz.class不可读的编译版本。您可以使用以下命令将其反编译为 Java 版本
javap -constants -p Fizz
Run Code Online (Sandbox Code Playgroud)
在包含的目录中Fizz.class
| 归档时间: |
|
| 查看次数: |
1134 次 |
| 最近记录: |