Scala学习之类和属性篇(一):定义类的主构造方法

风流意气都作罢 提交于 2020-03-12 21:31:36

在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"
              ^

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!