跳到内容

Scala/类

来自维基教科书,开放的书籍,为开放的世界

在 Scala 中,类是一种带有成员的类型,例如字段和方法。类实例可以使用值进行参数化,类可以使用类型进行参数化,这在Scala/类型参数中介绍。

一个简单的类示例

class SimpleClass
val simple1 = new SimpleClass
val simple2 = new SimpleClass

在第一行,关键字 "class" 用于开始类定义。 "class" 后面是类名 "SimpleClass"。这定义了一个名为 "SimpleClass" 的类。在第二行,一个名为 "simple1" 的值被赋值为表达式 "new SimpleClass" 的结果。 "new" 关键字根据类名创建一个实例并返回对该实例的引用,"new SimpleClass" 创建一个 "SimpleClass" 类型的新的实例。在第三行,一个名为 "simple2" 的值被赋值为表达式 "new SimpleClass" 的结果,创建了另一个 "SimpleClass" 类型的新的实例。因此,名为 "simple1" 和 "simple2" 的值各自保存对 "SimpleClass" 类型不同实例的引用。

类可以包含诸如字段之类的成员

class FieldsClass {
  val name = "SomeName"
  var num = 0
}

在第一行,声明了一个名为 "FieldsClass" 的类。在 "FieldsClass" 名字后面是 "{",它开始了类定义的主体。第二行声明了一个字段,在本例中是一个名为 "name" 的值,被赋值为字符串 "SomeName"。第三行也声明了一个字段,在本例中是一个名为 "num" 的变量,被赋值为数字 '0'。第四行包含一个关闭的 "}",它结束了类定义的主体。

可以使用 "." 访问类的成员

val fields1 = new FieldsClass
val fields2 = new FieldsClass
fields1.num = 3
fields2.num = 16
println("fields1.num is: " + fields1.num) //Prints "fields1.num is: 3".
println("fields2.num is: " + fields2.num) //Prints "fields2.num is: 16".

第一行和第二行声明了两个名为 "fields1" 和 "fields2" 的值,它们各自包含对 "FieldsClass" 实例的引用。第三行从 "fields1.num" 开始。"." 用于访问实例的成员。"." 之前的表达式指定实例,"." 后的名称指定成员。在本例中,指定的实例是 "fields1" 中引用的实例,指定的成员是字段 "num"。在 "fields1.num" 后面是一个赋值,它使用数字 3,将数字 3 赋值给第一个 "FieldsClass" 实例中的 "num" 字段。第四行与第三行类似,但数字 16 被赋值给第二个 "FieldsClass" 实例中的 "num" 字段。第五行和第六行访问两个实例并打印它们 "num" 字段的值,第一个实例的值为 3,第二个实例的值为 16。

类也可以有函数作为成员。这些函数被称为方法

class Counter {
  var count = 0
  def incrementAndGet = {count += 1; count}
}
val counter1 = new Counter
println("Count is: " + counter1.count) //Prints "Count is: 0".
println("Count is: " + counter1.incrementAndGet) //Prints "Count is: 1".
println("Count is: " + counter1.count) //Prints "Count is: 1".

在第一行到第四行,定义了一个名为 "Counter" 的类。第三行定义了一个方法,就像定义一个函数一样。在第五行,创建了一个新的 "Counter" 实例并赋值给名为 "counter1" 的值。

在第六行,打印实例的计数,即 0。在第七行,使用 "." 访问 "Counter" 的 "incrementAndGet" 方法,就像访问其他成员一样,并调用它。注意,该方法在将计数加 1 后将计数赋值给 incrementAndGet,因此打印的实例计数为 1。在第八行,再次打印实例计数,给出增加后的值 1。

构造函数

[编辑 | 编辑源代码]

类实例可以使用构造函数通过值进行参数化。一个简单的例子

class Circle(r:Double) {
  def area = math.Pi * math.pow(r, 2)
}
val circle1 = new Circle(10.0)
val circle2 = new Circle(20.0)
println("Circle 1's area: " + math.round(circle1.area)) //Prints "Circle 1's area: 314".
println("Circle 2's area: " + math.round(circle2.area)) //Prints "Circle 2's area: 1257".

第一行开始声明一个名为 "Circle" 的新类。在名字后面是 "(r:Double)",它定义了类的主要构造函数。主要构造函数包含一对圆括号,其中包含以逗号分隔的参数列表及其类型。在本例中,定义了一个名为 "r" 的参数,其类型为 "Double"。第二行定义了一个用于计算圆形面积的方法,该方法使用主要构造函数中定义的参数 "r",第三行结束了类定义。第四行定义了一个名为 "circle1" 的新值,并将其赋值为表达式 "new Circle(10.0)" 的结果。圆括号包含传递给 "Circle" 的主要构造函数的参数,在本例中为 "10.0"。因此,"circle1" 包含对 "Circle" 实例的引用,该实例使用 "r" 等于 "10.0" 进行参数化。第五行也是一样的,除了 "circle2" 实例的 "r" 等于 "20.0"。在第六行和第七行,打印圆形的面积。

在类中声明参数列表时,有三种限定符选项:无、"val" 和 "var"。如果没有限定符,如前所述,只能在类内部访问参数。如果限定符是 "val",则可以在类外部访问参数,但不能对其赋值。如果限定符是 "var",则可以在类外部访问参数,并且可以对其赋值。

在参数列表中使用 "val" 的示例

class Point(val x:Int, val y:Int, val z:Int)
val p1 = new Point(3, 10, -5)
println("p1's coordinates are: " + p1.x + ", " + p1.y + ", " + p1.z) //Prints "p1's coordinates are: 3, 10, -5".

在第一行中,所有参数都被 "val" 限定。在第二行中,构造了一个 "Point" 实例,在第三行中,在 "Point" 的定义之外访问了 "Point" 实例的参数。

在参数列表中使用 "var" 的示例

class Accumulator(var sum:Int)
val accumulator1 = new Accumulator(30)
println("Sum is: " + accumulator1.sum) //Prints "Sum is: 30".
accumulator1.sum += 50
println("Sum is: " + accumulator1.sum) //Prints "Sum is: 80".

辅助构造函数

[编辑 | 编辑源代码]

辅助构造函数是类的替代构造函数,在类中定义为名为 "this" 的方法。类可以有多个辅助构造函数,但它们应该具有不同的签名,并且必须调用之前定义的构造函数。

class Car(val color:String,val year:Int)
{
  def this(){
    this("Black",2010)   //Auxiliary constructor with defaults
  }

  def this(color:String) {
    this(color,2010)
  }

  def this(year:Int){
    this("Black",year)
  }
}

object Car {
   def main(args:Array[String])= {
    //You can instantiate the Car with different constructor signatures
    val blackCar = new Car()
    val redCar = new Car("Red")
    val defCar = new Car("Green", 2013)
    val oldCar = new Car(1990)
  }
}

在上面的示例中,我们有三个辅助构造函数。

华夏公益教科书