跳到內容

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)
  }
}

在上面的示例中,我們有三個輔助建構函式。

華夏公益教科書