這篇文章將介紹類的基礎知識
定義
Scala 中以 class 來作為類的聲明,在類中可以定義成員和方法,成員和方法可以有不同的可見性(這個會在后文詳述)。
scala> class Company {
| private var employeeCount = 0
| def getEmployeeCount(): Int = employeeCount
| def setEmployeeCount( count: Int)= {
| employeeCount = count
| }
|
| def m( i: Int ) {}
| def m( str: String ) {}
| }
defined class Company
構造器
Scala 中,類有一個主構造器,主構造器必須包含所需的所有參數。除了一個主構造器,還可以有0個或多個輔助構造器,輔助構造器又稱次構造器。輔助構造器命名為 this,其第一條語句必須調用主構造器或其他輔助構造器,來看下面的例子:
scala> class T ( x1: Int, y1: String, z1: Double ) {
| private val xx1 = x1
| private val yy1 = y1
| private val zz1 = z1
|
| def this ( x1: Int, y1: String ) {
| this( x1, y1, 1.0 )
| }
|
| def this ( x1: Int ) {
| this( x1, "" )
| }
| }
defined class T
還有一點需要注意的是,被調用的輔助構造函數的定義必須放在主動調用的輔助構造函數前面,不然會報錯:
scala> class T ( x1: Int, y1: String, z1: Double ) {
| private val xx1 = x1
| private val yy1 = y1
| private val zz1 = z1
|
| def this ( x1: Int ) {
| this( x1, "" )
| }
|
| def this ( x1: Int, y1: String ) {
| this( x1, y1, 1.0 )
| }
| }
<console>:13: error: called constructor's definition must precede calling constructor's definition
this( x1, "" )
^
不管輔助函數調來調去,最終都還是要調用到主構造函數,這確保了新實例的初始化邏輯一致。
如果在主構造函數的參數前加 var 或 val,該參數就成為實例的一個成員,這部分知識在Scala case class那些你不知道的知識有更詳細的介紹
重載
Scala 類方法允許重載,如類 Company 中的 m 方法。重載要求參數列表和返回類型不完全相同,但參數名可相同,這是因為編譯后是通過方法名、參數列表、返回類型綜合來區分各個方法的。
在方法重載時,有一點需要注意:對于『高級類型』,存在類型擦除機制,所謂的高級類型就是包含類型參數的類型,比如 List[A],下面這個例子可以展示了類型擦除:
scala> class Tmp {
| def m( data: List[Int] ) {}
| def m( data: List[String] ) {}
| }
<console>:9: error: double definition:
method m:(data: List[String])Unit and
method m:(data: List[Int])Unit at line 8
have same type after erasure: (data: List)Unit
def m( data: List[String] ) {}
^
報了有相同類型的參數的錯誤。
類型成員
Scala 允許你在類內部定義類型成員,在構造類實例的時候指定該類型成員對應的具體類型。類型成員可用于類內部的成員或函數,提供了更好的泛華能力,從下面這個簡單的例子可以看出:
scala> class T {
| type X
|
| def getClassName( x: X): String = {
| x.getClass.getTypeName
| }
| }
defined class T
scala> val x1 = new T{ type X = Int }
x1: T{type X = Int} = $anon$1@515f550a
scala> x1.getClassName(10)
res0: String = java.lang.Integer
scala> val x2 = new T{ type X = String }
x2: T{type X = String} = $anon$1@61a52fbd
scala> x2.getClassName("string")
res1: String = java.lang.String
當然,也可以在類外部定義類型變量,如:
scala> type L = List[Int]
defined type alias L
方法與成員同名
與 JAVA 不同,如果方法參數列表不為空,該方法可以與成員同名,如:
scala> class T {
| private val m = 0
|
| def m( i: Int ): Int = m + i
| }
defined class T