【《快學Scala》筆記】
1、Scala中的類是公有可見性的,且多個類可以包含在同一個源文件中;
1 class Counter{ 2 private var value = 0 //類成員變量必須初始化,否則報錯 3 4 def increment(){ //類中的方法默認是公有可見性 5 value += 1 6 } 7 8 def current() = value //對於類中的“取值方法”,在定義時可省略掉括號,直接 def current = value 9 }
Scala類的使用:
Scala的類在未提供構造器時,也會提供默認構造器;且在調用無參構造器或無參方法時可省略掉方法后的括號。
2、Scala類的每個字段都有getter和setter方法,私有字段的getter和setter默認是私有的,公有字段的getter和setter方法默認是公有的。
其中對於類中的屬性value,Scala類默認生成的getter方法名為 value,默認生成的setter方法名為 value_= 。使用時,我們可以重新定義獲取或設置屬性的方法。
例如,
1 class Clock{ 2 var hour = 0 3 var minute = 0 4 var second = 0 5 6 def getTime():String={ 7 return hour+":"+minute+":"+second 8 } 9 }
對於Clock類中的屬性,如 hour,其對應的getter方法為 hour ,其對應的setter方法名為 hour_=
【注:可以重新定義獲取Scala類中屬性的方法,但是最好不要與屬性默認對應的getter/setter方法重名,否則會報錯。】
3、對於Scala類中的val屬性,只有默認的getter方法;對於private屬性,其默認getter、setter都是private的。因而,對於不想提供setter方法的變量可以設置為val,對於不想提供getter、setter方法的變量可以設置為private。
4、注意,Scala類中,定義無參函數時,若函數聲明時省略了函數名后的括號(由於無參數,可以省略),調用時,必須參數無括號的形式,通過帶括號形式調用會報錯。如,
1 class Counter{ 2 var value = 0 3 4 def current = value 5 }
類Counter定義中,對於方法current,由於不接受參數,所以定義時省略了方法名current后的括號。此時,對於Counter的實例counter,調用current方法時,必須采用counter.current(無括號形式)。
5、對於Scala類中定義的字段,在Scala中實際為私有字段。(還有待進一步理解和驗證)
1 class Counter{ 2 var value = 0 3 val sum = 0 4 private var cnt = 1 5 6 //.... 7 }
在Counter類中,Scala在為Counter生成面向JVM的類時,對於value字段,會生成對應的私有字段value和公有的getter、setter方法;對於sum字段,會生成私有的final字段和公有的getter方法;對於cnt字段,會生成私有字段cnt和私有的getter、setter方法(貌似這個private聲明只是影響的Scala根據屬性生成的對應getter、setter的可見性)。
6、構造器
Scala的類可以有一個主構造器和多個輔助構造器。每個輔助構造器的名稱為this,每一個輔助構造器都必須以調用已經定義的輔助構造器或主構造器開始定義。
- 主構造器
如果一個類沒有顯示定義主構造器,則有一個默認的無參主構造器。
如定義一個Student類,
1 class Student(val name:String, var age:Int = 0, address:String = "", private var school:String = ""){ 2 var grade:Int = if( age>7 ) age-7 else 0 3 4 println(" I'm in main constructor. ") 5 6 def info() = " name is "+name+", age is "+age+", address is "+address 7 }
對於Scala類,主構造器的參數放置在類名后,由括號括起來。且對於主構造器中var、val、private 等標注的參數,都會成為類的對應字段,並生成對應的默認getter、setter方法。如Student類中的name、age、school等。對於主構造器中的未用var、val標注的參數,如果在類的任何一個方法用用到該參數,該參數將會轉換為類的字段,否則不會,如Student類的address屬性。
由於在Student類中的info方法中用到了參數address,所以Student共有name、age、address、school、grade等5個屬性,且Scala根據對應屬性的特點生成了默認的getter和setter方法。
對於主構造器的參數,也可以提供參數默認值。通過為主構造器提供默認值可減少輔助構造器的個數。
主構造器的函數體,是類中除了方法定義以外的其他語句,如在Student類的主構造器中,包含grade屬性的初始化和prinln這兩行語句。
Stuent類的使用。
- 輔助構造器
輔助構造器通過this來定義,且必須首先調用主構造器或者其他已經定義的輔助構造器。
1 class Person(val name:String){ 2 var age = 0 3 var sex:Char = 'f' 4 5 println("main constructor...") 6 7 def this(name:String, age:Int){ 8 this(name) //調用主構造器 9 this.age = age //使用this關鍵字 10 11 println(" auxiliary constructor1 ") 12 } 13 14 def this(name:String, age:Int, sex:Char){ 15 this(name, age) 16 17 this.sex = sex 18 19 println(" auxiliary constructor2 ") 20 } 21 }
【注:輔助構造器的參數前不能添加val、var標志,否則會報錯。】
- 私有主構造器
1 class Person private(val name:String){ 2 var age:Int = 1 3 4 def this(name: String, age:Int){ 5 this(name) 6 this.age = age 7 } 8 9 }
私有構造器通過在類名后用private關鍵字標注主構造器參數來標明。此時,可以通過輔助構造器來創建該類的對象。
7、嵌套類
1 class Family(val h_name:String, val w_name:String){ 2 class Husband(var name:String){ 3 println(" I'm a husband ") 4 } 5 6 class Wife(var name:String){ 7 println(" I'm a Wife ") 8 } 9 10 var husband = new Husband(h_name) 11 var wife = new Wife(w_name) 12 13 def info(){ 14 println( "husband: "+husband.name+", wife:"+wife.name ) 15 } 16 }
在Scala中,你幾乎可以在任何語法結構中嵌套任何語法結構,如在函數中定義函數,在類中定義類。
1、Scala中沒有靜態方法和靜態字段,但是可以用object語法來實現類似的功能。對象定義了某個類的單個實例。
Scala的object中可以用來實現類似的功能,用來存放工具函數或常量等。如,
1 object Sequence{ 2 private var next_num = 0 3 val threshold = 100 4 5 def getSequence() = { 6 next_num += 1 7 next_num 8 } 9 }
使用object中的常量或方法,通過object名直接調用,對象構造器在對象第一次被使用時調用(如果某對象一直未被使用,那么其構造器也不會被調用)。
object的構造器不接受參數傳遞。
2、伴生對象
可以將在Java類中定義的靜態常量、方法等放置到Scala的類的伴生對象中。伴生對象與類同名,且必須放置在同一源文件中。類可以訪問伴生對象私有特性,但是必須通過 伴生對象.屬性名 或 伴生對象.方法 調用。
伴生對象是類的一個特殊實例。
1 class Counter{ 2 def getTotalCounter()= Counter.getCount 3 } 4 5 object Counter{ 6 private var cnt = 0 7 8 private def getCount()= cnt 9 }
如在類Counter訪問其伴生對象的石油方法getCount,必須通過 Counter.getCount() 的方式調用。
3、對象可以繼承或擴展多個特質
1 abstract class Person(var name:String, var age:Int){ 2 def info():Unit 3 } 4 5 object XiaoMing extends Person("XiaoMing", 5){ 6 def info(){ 7 println(" name is "+name+", age is "+age) 8 } 9 }
4、apply方法
當遇到 object(參數1, 參數2,....,參數n)的形式的調用時,apply方法便會被調用。
5、main方法——Scala程序的入口
main方法定義在object中,形式如下:
1 object HelloWorld{ 2 def main(args: Array[String]){ 3 println("Hello World!") 4 } 5 }
可以通過scalac 源文件名,然后通過 scala 類名 來執行主程序。
6、還可以通過擴展特質App來運行指定代碼
1 object HelloWorld2 extends App{ 2 println(" A 'Hello world' from HelloWorld2 ") 3 }
通過擴展App特質的方式執行程序時,將要執行的程序放到了object的主構造器中。
7、枚舉
Scala並沒有定義枚舉類型,但是可以通過定義擴展Enumeration的對象,並用Value方法初始化枚舉類中的所有可選值,提供枚舉。
1 object TrafficeLight extends Enumeration{ 2 val Red, Yellow, Green = Value 3 4 }
上述實例中的val Red, Yellow, Green = Value語句,相當於
1 val Red = Value 2 val Yellow = Value 3 val Green = Value
用Value方法初始化枚舉類變量時,Value方法會返回內部類的新實例,且該內部類也叫Value。另外,在調用Value方法時,也可傳入ID、名稱兩參數。如果未指定ID,默認從零開始,后面參數的ID是前一參數ID值加1。如果未指定名稱,默認與屬性字段同名。
1 object TrafficLight extends Enumeration{ 2 val Red = Value(1, "Stop") 3 val Yellow = Value("Wait") //可以單獨傳名稱 4 val Green = Value(4) //可以單獨傳ID 5 }
上例中,Yellow屬性就僅定義了名稱,Green僅定義ID。
參數在不指定名稱時,默認參數的Value為字段名。
【注:枚舉類型的值是, 對象名.Value ,如上例中的枚舉類型是 TrafficLight.Value。】
8、通過id方法獲取枚舉類型值的ID
9、通過values方法獲取所有枚舉值的集合
10、通過ID來獲取對應的枚舉對象