我正在尝试使用Scala,发现了三个有趣的事情(标题是第三个)。
1. 声明为val的局部变量并不被解释为final。
class HowAreVarAndValImplementedInScala {
var v1 = 123
val v2 = 456
def method1() = {
var v3 = 123
val v4 = 456
println(v3 + v4)
}
}
如果我将上述Scala代码编译为字节码,然后将其反编译为Java,它看起来是这样的:
public class HowAreVarAndValImplementedInScala
{
private int v1 = 123;
private final int v2 = 456;
public int v1()
{
return this.v1;
}
public void v1_$eq(int x$1) { this.v1 = x$1; }
public int v2() { return this.v2; }
public void method1() {
int v3 = 123;
int v4 = 456;
Predef..MODULE$.println(BoxesRunTime.boxToInteger(v3 + v4));
}
}
我们可以看到v2是最终版本,但v4不是,为什么?
Scala编译器针对.NET在许多(如果不是全部)公共实例方法中添加了override关键字。
如果我们将上面的Scala代码编译成CIL,然后反编译成C#,就像这样:
public class HowAreVarAndValImplementedInScala : ScalaObject
{
private int v1;
private int v2;
public override int v1()
{
return this.v1;
}
public override void v1_$eq(int x$1)
{
this.v1 = x$1;
}
public override int v2()
{
return this.v2;
}
public override void method1()
{
int v3 = 123;
int v4 = 456;
Predef$.MODULE$.println(v3 + v4);
}
public HowAreVarAndValImplementedInScala()
{
this.v1 = 123;
this.v2 = 456;
}
}
所有公共实例方法(不包括构造函数)都被标记为重写,为什么?这是必要的吗?
针对 .net 的 Scala 编译器丢失了 val 的含义。
在上面的 C# 代码中,我们可以看到 v2 只是一个普通字段,而在 Java 计数器部分中,v2 被标记为 final,难道 Scala 编译器为 .net 不应该将 v2 标记为 readonly 吗?(有 bug 吗?)
final
在局部变量中没有运行时影响,但强调你不会改变一个值。相比之下,final
字段暗示它们在构造函数执行后被初始化。因此,我猜测对于机器来说这对于v4
来说是无关紧要的,因此被省略了,而在Java中v2
必须是final
。然而我还不肯定到足以将其作为答案。 - Matthias Meid