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的方法非常类似,都是定义在类上的行为。但是也有以下区别点:

  1. 指定方法的访问控制(可见性)
  2. 给方法参数指定缺省值的能力
  3. 方法调用时指定参数名传参的能力
  4. 如何声明方法可能抛出的异常
  5. 可变参数的使用

5.1 控制方法作用域

Scala中的方法缺省值为public,按照“最严格”到“最开放”的顺序,Scala提供以下作用域级别:

  1. private[this] ----- 仅对当前实例可见
  2. private ----- 对当前类的所有实例可见
  3. protected ----- 对当前类及其所有子类的实例可见。该点与Java不同,Java中protected同时对同一个包下所有类可见,而Scala不可以
  4. private[packageName](包内可见性) ------ 对*.packageName包下所有类可见
  5. 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 创建接受变参的方法

为了让方法更加灵活,可以将方法参数定义为接受多个参数

  1. 在参数类型后面加上一个*。eg: def printAll(strings : String*)
  2. 使用_*来适配一个序列。 eg : def printlnAll(fruits : _*)。从而使得它可以被当作变参传给一个方法
  3. 变参必须是方法签名中的最后一个参数

代码

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)。为了支持这种风格的代码,需要:

  1. 如果类可能会被扩展,则把this.type作为链式调用风格方法的返回值类型。
  2. 如果类不会被扩展,则把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
  }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值