类和构造函数

类是一个面向对象编程概念,提供了一个高级编程抽象。从本质上来说,类是代码组织技术,将数据和所有数据的操作绑定在一起。从概念上来说,类代表一个属性和行为的实体。类是在运行时创建对象的模板,对象是类的具体实例。在源代码中定义一个类,而一个对象则存在于运行时。

面向对象编程并不新鲜,但是Scala增加了一些其他静态类型语言中没有的新特性。

类和构造函数

在Scala 中类与其它面向对象语言相似。类定义由字段声明和方法定义组成。字段是一个变量,用于存储对象的状态(数据),方法包含可执行代码,它是定义在类中的一个函数,可以提供对字段的访问,并更改对象的状态。

使用关键字class 定义一个类。类的定义从类名开始,后跟一对小括号,括号内由逗号分隔的类参数,然后是一对花括号,花括号内包含字段和方法。

类声明与在Java或c#中声明的方式不同:不仅声明了类,而且声明了它的主构造函数。下面的示例代码定义了一个代表汽车类的Car及其主构造函数:

class Car(val make: String, val model: String, val color: String) 

在Scala中,类体是可选的。可以创建没有任何类主体的类。与Java或c#一样,Scala也使用new关键字来创建类的实例。

val mustang = new Car("福特","野马","红色")
mustang.make
mustang.model
mustang.color

当构造函数的参数以var为前缀时,Scala创建可变实例变量。val和var前缀是可选的,当没有指定val或var关键字时,构造函数的参数会被当作私有实例值,因此不能从类的外面进行访问:

class Car(val make: String, val model: String, color: String) 

val mustang = new Car("福特","野马","红色")
mustang.make
mustang.model
// mustang.color   // 不能访问

注意,当Scala创建实例值或变量时,它还为它们创建访问器。当使用val和var定义一个字段时,默认会创建一个getter方法;并且对于var,还创建了一个额外的setter方法。

class Car(val make: String, val model: String, var color: String) 

val mustang = new Car("福特","野马","红色")
mustang.color   

mustang.color = "黄色"
mustang.color

在类中也可以定义成员方法,如下面的代码所示:

class Car(val make: String, val model: String, var color: String) {

  // 成员方法:重新油漆
  def repaint(newColor: String) = {
    color = newColor
  }

  // 成员方法:输出汽车的详细信息
  def printCarDetails() = println(s"制造商:$make, 车型:$model, 颜色:$color")
}

下面的代码使用关键字new 创建类Car的实例:

val mustang = new Car("福特","Mustang","红色")
mustang.printCarDetails

val corvette = new Car("通用","Corvette","黑色")
corvette.printCarDetails

mustang.repaint("黄色")
mustang.printCarDetails

在Scala中,类并不声明为public。Scala源文件可以包含多个类,所有这些类都具有公有可见性。类中的成员方法默认是公有的。

Scala类的构造器分为主构造函数和辅助构造函数。scala中把类名后面的一对{}括起来的内容称为主构造函数的函数体,默认的主构造函数为空参构造器。在Scala中,类的主构造函数与类定义内联编码。主构造函数是在创建对象实例时需要直接或间接地从重载构造函数调用的构造函数。

当主构造器满足不了我们的需求之后,我们就可以创建更多的辅助构造器来配合我们的业务,辅助构造器的函数名是this。在一个类中只能有一个主构造器,可以有若干重载的辅助构造器。注意,在辅助构造中的第一句话,必须是调用该类的主构造器或者其他辅助构造器 - this(参数)。

class Employee(var name:String, var age:Int) {     // 主构造器

  private var married:Boolean = false

  // 辅助构造器1
  def this() {
    this("新员工", 0)      // 在辅助构造中的第一句话,必须是调用该类的主构造器或者其他辅助构造器
    println("this is 辅助构造器")
  }

  // 辅助构造器2
  def this(isMarried:Boolean) {
    this()                  // 在辅助构造中的第一句话,调用了该类的辅助构造器1
    married = isMarried
    println(s"this($isMarried) 是另外一个构造器")
  }

  def show() = println(s"姓名:$name, 年龄:$age, 婚否:$married")
}

下面的代码测试上面这个类:

val emp = new Employee("张三", 23)
emp.show 
    
val emp2 = new Employee()
emp2.show
    
val emp3 = new Employee(true)
emp3.show

定义类Money:

class Money(val amount:Int)
val notMuch = new Money(2)  // 创建类的实例
notMuch.amount=3

class Money(var amount:Int)
val notMuch = new Money(2)
notMuch.amount=3
notMuch.amount

定义银行类:

class BankAccount(var balance:Double=0) {

  def deposit(amount: Int): Unit = {
    if (amount > 0) balance = balance + amount
  }

  def withdraw(amount: Double): Double =
    if (0 < amount && amount <= balance) {
      balance = balance - amount
      balance
    } else throw new Error("insufficient funds")

}

因为Scala 运行在JVM 上,并不需要显式地删除一个对象。Java 垃圾回收器自动地删除不再使用的对象。

注:在Java中,有原始类型如int、char或boolean等(总共有八个原始数据类型),但是,在Scala中,只有类和对象。


《PySpark原理深入与编程实战》