Scala實戰專欄 (五) ——— 方法
scala-basic 基礎篇
@author 魯偉林
Scala基礎知識介紹,主要包括《Scala程式設計實戰》的基礎章節
GitHub地址: https://github.com/thinkingfioa/scala-in-action
本人部落格地址: http://blog.csdn.net/thinking_fioa/article/details/78265745
第5章 方法
Scala的方法和Java的方法非常類似,都是定義在類上的行為。但是也有以下區別點:
- 指定方法的訪問控制(可見性)
- 給方法引數指定預設值的能力
- 方法呼叫時指定引數名傳參的能力
- 如何宣告方法可能丟擲的異常
- 可變引數的使用
5.1 控制方法作用域
Scala中的方法預設值為public,按照“最嚴格”到“最開放”的順序,Scala提供以下作用域級別:
- private[this] ----- 僅對當前例項可見
- private ----- 對當前類的所有例項可見
- protected ----- 對當前類及其所有子類的例項可見。該點與Java不同,Java中protected同時對同一個包下所有類可見,而Scala不可以
- private[packageName](包內可見性) ------ 對*.packageName包下所有類可見
- public(公開方法) ----- 如果方法宣告上沒有訪問修飾符,方法就是公開級別。任何包下任何類都可以訪問
5.2 呼叫父類的方法
為了減少重複程式碼,希望呼叫一個父類或者特質中的方法。通常情況下Scala直接呼叫父類的方法和Java是相同的:用super代表父類。但也存在不同點:當類繼承了多個特質,並且特質實現了相同的方法,需要制定使用的特質。
程式碼:
trait Human { def hello : String = "the Human trait" } trait Mother extends Human { override def hello: String = "Mother" } trait Father extends Human { override def hello: String = "Father" } class Child extends Human with Mother with Father { def printSupper : String = super.hello def printMother : String = super[Mother].hello def printFather : String = super[Father].hello def printHuman : String = super[Human].hello def print(): Unit = { println(s"supper $printSupper") println(s"Mother $printMother") println(s"Father $printFather") println(s"Human $printHuman") } } object Child { def apply() = new Child() } object Method5P2 { def main(args: Array[String]): Unit = { val child : Child = Child() child.print() } }
注意
當使用supper[traitName].methodName來指定使用哪個特質上的方法時,目標特質必須被當前類通過extends或者with關鍵字擴張,否則編譯失敗。
5.3 方法引數預設值
希望給方法的引數設定預設值,因此呼叫此方法是可以省略傳參。
程式碼
class Connection {
def connection(timeout : Int = 5000, protocol : String = "http"): Unit = {
println("timeout = %d, protocol = %s".format(timeout, protocol))
}
}
object Method5P3 {
def main(args: Array[String]): Unit = {
val connection : Connection = new Connection()
connection.connection()
}
}
5.4 使用引數名
偏向於在呼叫方法時指定引數名
程式碼
class Pizza {
var size = 12
var price = 200
def update(currSize : Int, currPrice : Int) : Unit = {
this.size = currSize
this.price = currPrice
}
def print() : Unit = {
println(s"size $size, price $price")
}
}
object Method5P4 {
def main(args: Array[String]): Unit = {
var pizza : Pizza = new Pizza()
pizza.update(currPrice = 15, currSize = 100)
pizza.print()
}
}
5.5 定義一個返回多個值(Tuples)的方法
希望從一個方法中返回多個值,在Java中,由於無法返回多值,通常使用一個"臨時包裝類"中返回,Scala中只需要以tuple的形式返回即可。
程式碼
class MoreReturnValue() {
def fetchMoreReturn() : (String, Int, Int) = {
("thinking", 23, 125)
}
}
object Method5P5 {
def main(args: Array[String]): Unit = {
val moreReturnValue : MoreReturnValue = new MoreReturnValue()
val (name, age, weight) = moreReturnValue.fetchMoreReturn()
println(s"name is $name, age is $age, weight is $weight")
}
}
5.6 生成Java型別的getter/setter方法 ----- BeanProperty
使用scala.beans.BeanProperty註解,自動生成和Java類似的getter/setter方法。在JSON轉換時非常有用
程式碼
class Pizza5P6(@BeanProperty var price : Int, @BeanProperty var size:Int) {
}
object Method5P6 {
def main(args: Array[String]): Unit = {
val pizza : Pizza5P6 = new Pizza5P6(100, 12)
println("price "+pizza.getPrice)
println("size "+pizza.getSize)
}
}
5.7 建立接受變參的方法
為了讓方法更加靈活,可以將方法引數定義為接受多個引數
- 在引數型別後面加上一個*。eg: def printAll(strings : String*)
- 使用_*來適配一個序列。 eg : def printlnAll(fruits : _*)。從而使得它可以被當作變參傳給一個方法
- 變參必須是方法簽名中的最後一個引數
程式碼
class Method5P7 {
def printAll(strings : String*): Unit = {
strings.foreach(println)
}
}
object Method5P7 {
def main(args: Array[String]): Unit = {
val method : Method5P7 = new Method5P7()
method.printAll("thinking", "fioa", "ppp")
val fruits = List("apple", "apple2")
method.printAll(fruits : _*)
}
}
5.8 方法的異常宣告
給方法增加異常宣告,為了讓呼叫者知道也為了可以從Java程式碼呼叫。使用@throws註解宣告可能丟擲的異常。值得注意的是,Scala中不強制要求方法宣告可能丟擲的受檢異常,也不要求呼叫者捕捉受檢異常。但是如果異常發生,執行緒執行會停止。
程式碼
class Method5P8 () {
@throws[UnsupportedOperationException]
@throws[NullPointerException]
def playSound(): Unit = {
}
}
5.9 支援鏈式呼叫程式設計風格
鏈式呼叫風格的程式碼能夠把方法呼叫連結起來。如: person.setFirstName("thinking").setAge(23)。為了支援這種風格的程式碼,需要:
- 如果類可能會被擴充套件,則把this.type作為鏈式呼叫風格方法的返回值型別。
- 如果類不會被擴充套件,則把this從鏈式呼叫方法中返回出來。
5.9.1 類會被擴充套件
如果類可以被擴充套件,把方法的返回值顯式指定為this.type能夠確保鏈式呼叫能在自類中仍能正常工作
程式碼
class Person5P9 {
protected var fname = ""
protected var lname = ""
def setFirstName(firstName : String) : this.type = {
this.fname = firstName
this
}
def setLastName(lastName : String) : this.type = {
this.lname = lastName
this
}
}
class Employee extends Person5P9 {
protected var role = ""
def setRole(role : String) : this.type = {
this.role = role
this
}
}
5.9.2 類不會擴充套件
如果確定類不會被擴充套件,就沒有必要將setXXX方法的返回值型別指定為this.type,只需在每個鏈式方法的最後返回this即可
程式碼
class Employee {
protected var role = ""
def setRole(role : String) = {
this.role = role
this
}
}