《快学Scala》——类

2019-03-28

Scala类最简单的形式看上去和Java或C++相似:

class Person {
  // val 修饰的属性,系统会自动生成get方法
  val id:String = "1234" // 必须初始化字段
  // var 修饰的属性,系统会自动生成get和set方法
  var name:String = ""
  // private var 修饰的属性,系统会自动生成private修饰的get和set方法
  // 相当于类的私有字段
  private var gender:Int = 0
  // private[this] 修饰的属性,系统不会生成get和set方法
  // 只有当前对象才能访问
  private[this] var age:Int = 0
}

class Counter {
  private var value:Int = 0  
  def increment():Int { // 方法默认是公有的
    value += 1
  }
  def current():Int = value
}

注: 在Scala中类并不声明为public。Scala源文件可以包含多个类,所有这些类都具有公有可见性。

带getter和setter的属性

Scala对每个字段都提供了gettersetter方法。如下:

class Person {
  var age:Int = 0
}

Scala生成面向JVM的类,其中有一个公有的age字段以及相应的gettersetter方法。这两个方法也是公有的,因为我们并没有将age声明成private。(对于私有字段生成的gettersetter也是私有的)
注: 在Scala中,gettersetter分别叫做ageage_=。 自己也可以重新定义gettersetter方法,如下:

class Person {
  private var privateAge:Int = 0
  def getAge():Int = this.privateAge
  def setAge(newValue:Int) = {
    if(newValue > privateAge) {
      privateAge = newValue
    }
  }
}

注: 如果字段是私有的,则gettersetter是私有的;如果字段是val,则只有getter方法被生成;如果不需要gettersetter,可以使用对象私有字段(该类的方法只能访问到当前对象的该字段,而不能访问同样是该类的其他对象的该字段),将该字段声明为private[this]

总结: 在实现属性是可以有四种选择,如下:

  • var foo: Scala自动生成要给getter和一个setter。
  • val foo: Scala自动生成要给getter
  • 由你自己来定义foofoo_=方法
  • 由你自己来定义foo方法

Bean属性

使用@BeanProperty注解来为字段生成符合JavaBeans规范的getter/setter方法。使用该注解后,将会生成4个方法:Scala的getter/setter和JavaBeans规范的getter/setter(如果是val声明,就没有setter部分了)。
针对字段生成的方法

构造器

在Scala中,有两种构造器,主构造器(primary constructor)和辅助构造器(auxiliary constructor)。

辅助构造器

  • 名字是this
  • 辅助构造器必须以对已经定义的辅助构造器或主构造器的调用开始
class Person {
  private var name:String = ""
  private var age:Int = 0

  def this(name: String) {
    this() // 调用主构造器
    this.name = name
  }

  def this(name: String, age: Int) {
    this(name)  // 调用辅助构造器
    this.age = age
  }
}

主构造器

Scala中每个类都有主构造器,并且是与类定义混合在一起的。

  • 主构造器的参数,是类名后()内的内容。
    class Person(val name: String, val age: Int) {
        // val name: String, val age: Int 部分就是主构造器的参数
    }
    
  • 主构造器会执行类定义中的所有语句。
    class Person(val name: String, val age: Int) {
        println("Just .......")  
        def description = name + " is " + age + " years old"
        // 上述语句是主构造器的一部分
        ...
    }
    

如果类名之后没有参数,则该类具备一个无参主构造器。这样一个构造器仅仅是简单的执行类体中的所有语句。
如果主构造器参数不带valvar,这样的参数如何处理取决于它们在类中如何被使用。如果不带valvar的参数被方法使用了,它会变为对象私有字段;如果没有被方法使用,则被当成一个普通的参数,不升级成字段。
针对主构造器参数生成的字段和方法
注: 可以将主构造器变为私有的,将private关键字放在圆括号前:

class Person private(val id: Int) { ... }  // 这样一来类用户就必须通过辅助构造器来构造Person对象