要研究此问题,我们可以反向工程请参阅“编译器会做什么?” :)
为此,我们与内容 class C(x: Int){}
运行编译类C.scala
:
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
关键字,则类变量将被定义为mutable:这是错误的。证明我们可以更深入一级地进行拆解。通过运行:
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
,因此,不可变。
第一段中的所有3个声明都是错误的:'val'和'var'并不总是公开的,这只是默认值;没有修饰符,你可能有也可能没有一个字段(它取决于参数是否用在任何方法中),但它无论如何都是不可变的。 –
我同意他们并不总是公开的;你可以使用'private'修改,但我认为答案的重点仍然存在,在这种情况下,它们是默认公开的。虽然我可以编辑答案。我愿意编辑建议。关于方法,我不确定我完全理解。当你使用像class A(val t:Int)和't'这样的东西时,这个例子会是类的属性/字段吗? –
当你有'class A(i:Int)'时,类'A'没有'i'的字段。 'i'只是一个(不可变的)构造函数参数。当你有'class A(i:Int){def foo = i}'时,类'A'具有一个私有的不可变字段'i'。 –