scala-basic 基础篇
@author 鲁伟林
Scala基础知识介绍,主要包括《Scala编程实战》的基础章节
GitHub地址: https://github.com/thinkingfioa/scala-in-action
本人博客地址: http://blog.youkuaiyun.com/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
}
}