Scala 默认构造函数';s的参数转换为字段?
我在Scala REPL中运行简单的代码,它创建了两个类,每个类都有一个Scala 默认构造函数';s的参数转换为字段?,scala,Scala,我在Scala REPL中运行简单的代码,它创建了两个类,每个类都有一个Int值x。以下是方法: scala> class C(x: Int){} defined class C scala> new C(100).x <console>:13: error: value x is not a member of C new C(100).x ^ scala> class D(val x: Int){} defi
Int
值x
。以下是方法:
scala> class C(x: Int){}
defined class C
scala> new C(100).x
<console>:13: error: value x is not a member of C
new C(100).x
^
scala> class D(val x: Int){}
defined class D
scala> new D(100).x
res1: Int = 100
scala>C类(x:Int){
定义的C类
scala>新的C(100).x
:13:错误:值x不是C的成员
新C(100.x)
^
scala>class D(val x:Int){}
定义的D类
scala>新的D(100).x
res1:Int=100
我的理解是,对于类C
而言,变量x
将成为可变变量(var
默认情况下),而对于类D而言,则是不可变变量。然而,我遇到了这个问题,x
不是C
的成员
这是怎么回事?Scala类中的属性可以有以下修饰符:
使属性不可变;它始终是公共的-这是有意义的,因为值不能更改val
使属性可变并公开var
- 没有修饰符使属性可变且私有
// no modifier
class A(x: Int) {
def print() = {
x += 1 // this i fine, it's mutable
println(x)
}
}
val a = new A(3)
// a.x - compile error, it's private
// var
class A(var x: Int) {
def print() = {
x += 1 // this is fine, it's mutable
println(x)
}
}
val a = new A(3)
a.x // you can do this since it's public (modifier var)
// val
class A(val x: Int) {
def print() = {
// x += 1 // can't do this, it's immutable
println(x)
}
}
val a = new A(3)
a.x // you can do this since it's public (modifier val)
有关构造函数和类的详细信息:Scala类中的属性可以具有以下修饰符:
使属性不可变;它始终是公共的-这是有意义的,因为值不能更改val
使属性可变并公开var
- 没有修饰符使属性可变且私有
// no modifier
class A(x: Int) {
def print() = {
x += 1 // this i fine, it's mutable
println(x)
}
}
val a = new A(3)
// a.x - compile error, it's private
// var
class A(var x: Int) {
def print() = {
x += 1 // this is fine, it's mutable
println(x)
}
}
val a = new A(3)
a.x // you can do this since it's public (modifier var)
// val
class A(val x: Int) {
def print() = {
// x += 1 // can't do this, it's immutable
println(x)
}
}
val a = new A(3)
a.x // you can do this since it's public (modifier val)
关于构造函数和类的更多信息:要研究这个问题,我们可以进行反向工程,看看“编译器会做什么?”:) 为此,我们正在编译包含以下内容的类
C.scala
C类(x:Int){}
通过运行:
scalac C.scala
这将生成C.class
。
现在,我们可以使用javap来查看编译器将生成什么
运行
javap-pc.class
将产生:
public class C {
public C(int);
}
如果我们重复整个过程
D类(val x:Int){}
我们将作出以下让步:
public class D {
private final int x;
public int x();
public D(int);
}
我们可以看到区别在于关键字val
告诉类创建一个getter方法
回到您的假设,如果没有val
关键字,类变量将被定义为可变的:这是错误的。为了证明我们可以更深入地了解这个问题。通过运行:
javap-p-vc.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
}
{
公共图书馆(国际);
描述符:(I)V
旗帜:ACC_PUBLIC
代码:
堆栈=1,局部变量=2,参数大小=2
0:aload_0
1:invokespecial#14//方法java/lang/Object。“:()V
4:返回
LocalVariableTable:
起始长度插槽名称签名
050本信用证;
0 5 1 x 1
LineNumberTable:
第4行:0
第2行:4
方法参数:
姓名标志
x决赛
}
您可以清楚地看到,类变量
x
仍然声明为final
,因此是不可变的。要研究这个问题,我们可以通过反向工程查看“编译器会做什么?”:)
为此,我们正在编译包含以下内容的类C.scala
C类(x:Int){}
通过运行:
scalac C.scala
这将生成C.class
。
现在,我们可以使用javap来查看编译器将生成什么
运行
javap-pc.class
将产生:
public class C {
public C(int);
}
如果我们重复整个过程
D类(val x:Int){}
我们将作出以下让步:
public class D {
private final int x;
public int x();
public D(int);
}
我们可以看到区别在于关键字val
告诉类创建一个getter方法
回到您的假设,如果没有val
关键字,类变量将被定义为可变的:这是错误的。为了证明我们可以更深入地了解这个问题。通过运行:
javap-p-vc.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
}
{
公共图书馆(国际);
描述符:(I)V
旗帜:ACC_PUBLIC
代码:
堆栈=1,局部变量=2,参数大小=2
0:aload_0
1:invokespecial#14//方法java/lang/Object。“:()V
4:返回
LocalVariableTable:
起始长度插槽名称签名
050本信用证;
0 5 1 x 1
LineNumberTable:
第4行:0
第2行:4
方法参数:
姓名标志
x决赛
}
您可以清楚地看到,类变量
x
仍然声明为final
,因此是不可变的。第一段中的所有3个声明都是错误的:val
和var
并不总是公共的,这只是默认值;如果没有修饰符,您可能有也可能没有字段(这取决于参数是否在任何方法中使用),但无论如何它都是不可变的;您可以使用private
modified,但我认为答案仍然存在,在这种情况下,它们默认为公共的。不过我可以编辑答案。我愿意编辑建议。关于方法,我不确定我是否完全理解。当您使用类似class A(val t:Int)
的内容,并且t
将是类的属性/字段时,示例是什么?当您有class A(i:Int)
时,classA
没有i
的字段i
只是一个(不可变)构造函数参数。当您有class A(i:Int){def foo=i}
时,classA
为i
提供了一个私有的不可变字段。我明白了,谢谢。请在这里阅读答案:。虽然我回答的重点是