在Scala中直接在类名后面跟上参数,即可定义类的主构造方法。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person(var firstName: String, var lastName:String) {
println("The construct begins.")
var age = 18
println(this)
println("The construct ends.")
override def toString = s"$firstName $lastName is $age years old."
}
// Exiting paste mode, now interpreting.
defined class Person
接下来我们通过主构造方法来实例化这个类,看看发生了什么。所有定义在类体内部的可执行性代码都被执行了,也就是说整个类内部都是这个主构造方法的方法体。
scala> val p = new Person("wang", "wei")
The construct begins.
wang wei is 18 years old.
The construct ends.
p: Person = wang wei is 18 years old.
至此,主构造方法的参数和方法体部分都已经说明了。
接下来我们尝试访问一下类的几个属性,你会发现可以直接用类名加属性名来访问。
scala> p.firstName
res4: String = wang
scala> p.lastName
res5: String = wei
scala> p.age
res6: Int = 18
由于所有属性都是使用var关键字来定义的,所以我们可以改变他们的值。
scala> p.firstName = "Li"
p.firstName: String = Li
scala> p.lastName = "Ming"
p.lastName: String = Ming
scala> p.age = 20
p.age: Int = 20
scala> println(p)
Li Ming is 20 years old.
接下来我们讨论一下主构造方法中参数的可见性问题。
使用var修饰的主构造方法参数,因为是可变的所有Scala会自动为其生成get和set方法。
scala> class Person(var name: String)
defined class Person
scala> val p = new Person("Ming");
p: Person = Person@25d3cfc8
scala> p.name
res8: String = Ming
scala> p.name = "Ning"
p.name: String = Ning
scala> p.name
res9: String = Ning
使用val修饰的主构造方法参数,因为是不可变的所有Scala不会为其生成set方法。
scala> class Person(val name: String)
defined class Person
scala> val p = new Person("Ming")
p: Person = Person@5edc70ed
scala> p.name
res10: String = Ming
scala> p.name = "Ning"
<console>:13: error: reassignment to val
p.name = "Ning"
^
不适用val或者var关键字修饰的主构造方法参数,Scala将采取最严格的访问限制,set和get方法都不会被提供,并且这个参数是不可变的。
scala> class Person(name: String)
defined class Person
scala> val p = new Person("Ming")
p: Person = Person@36aa52d2
scala> p.name
<console>:14: error: value name is not a member of Person
p.name
^
scala> p.name = "Ning"
<console>:15: error: value name is not a member of Person
val $ires8 = p.name
^
<console>:13: error: value name is not a member of Person
p.name = "Ning"
^
如果强行为无关键字修饰的主构造方法参数添改变其值的方法,会导致编译报错。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person(name: String) {
def getName = println(name)
def setName(_name: String) { this.name = _name }
}
// Exiting paste mode, now interpreting.
<console>:13: error: reassignment to val
def setName(_name: String) { this.name = _name }
^
在val或者var关键字前面加上private关键字,那么Scala同样不会为这个参数生成get和set方法。那么我们如果想定义一个可变但不可访问的参数该怎么办呢:private var argument。这样Scala不会为其生成set和get方法,但是你可以在类的内部自定义一些方法来改变这个参数的值。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Person(private var name: String) {
def printName = println(name)
def setName(_name: String) { this.name = _name }
}
// Exiting paste mode, now interpreting.
defined class Person
scala> val p = new Person("Ming")
p: Person = Person@5d342959
scala> p.printName
Ming
scala> p.setName("Ning")
scala> p.printName
Ning
总结:主构造方法参数可见性一共有这么几种
- 使用var修饰:Scala会为其生成get和set方法。
- 使用val修饰:Scala会为其生成get方法。
- 不使用修饰:Scala不会为其生成get和set方法,并且参数值不可改变。(效果等同于private val)
- 使用private修饰:Scala不会为其生成get和set方法,但参数可变性由var和val来决定。
注意:使用case class来定义的类的主构造方法参数,如果你不适用任何修饰默认使用val修饰。
scala> case class Person(name: String)
defined class Person
scala> val p = new Person("Ming")
p: Person = Person(Ming)
scala> p.name
res15: String = Ming
scala> p.name = "Ning"
<console>:14: error: reassignment to val
p.name = "Ning"
^