《快学Scala》第六章——对象 学习笔记

本章要点概览:

用对象作为单例或存放工具方法。

  • 类可以拥有一个同名的伴生对象。
  • 对象可以扩展类或特质。
  • 对象的apply方法通常用来构造伴生类的新实例。
  • 如果不想显示定义main方法,可以用扩展App特质的对象。
  • 可以通过扩展Enumeration对象来实现枚举。

6.1 单例对象

Scala没有静态方法或静态字段,可以用object这个语法结构来达到同样的目的。对象定义了某个类的单个实例,包含想要的特质。例如:
object Accounts{
    private var lastNumber = 0
    def newUniqueNumber() = { lastNumber += 1;lastNumber }
}
当在应用程序中需要一个新的唯一账号时,调用Accounts.newUniqueNumber()即可。
对象的构造器在该对象第一次被使用时调用。如果一个对象从未被使用,那么其构造器也不会被执行。
对象本质上可以拥有类的所有特性——甚至可以扩展其他类或特质。只有一个例外:不能提供构造器参数。
对于任何在Java或C++中会使用单例的地方,在Scala中都可以用对象来实现:
  • 作为存放工具函数或常量的地方。
  • 高效地共享单个不可变实例。
  • 需要用单个实例来协调某个服务时(参考单例模式)。

说明:Scala提供的是工具,可以做出好的设计,也可以做出糟糕的设计,需要做出自己的判断。

6.2 伴生对象

在Java或C++中,通常会用到既有实例方法又有静态方法的类。在Scala中,可以通过类和与类同名的“伴生”对象来达到同样的目的。
class Account{
    val id = Account.newUniqueNumber()
    private var balance = 0.0
    def deposit(amount: Double) { balance += amount }
    ......
}

object Account{      //伴生对象
    private var lastNumber = 0
    private def newUniqueNumber() = { lastNumber += 1; lastNumber }
}
类和它的伴生对象可以相互访问私有特性。它们必须存在于同一个源文件中。
说明:类的伴生对象可以被访问,但并不在作用域当中。如上面的例子,Account类必须通过Account.newUniqueNumber()而不是newUniqueNumber()来调用伴生对象的方法。

提示:在REPL中,要同时定义类和对象,必须使用黏贴模式。键入:
:paste
然后键入或黏贴类和对象的定义,最后一Ctrl + D退出黏贴模式。

6.3 扩展类或特质的对象

一个object可以扩展类以及一个或多个特质,其结果是一个扩展了指定类以及特质的类的对象,同时拥有在对象定义中给出的所有特性。一个有用的场景是给出可被共享的缺省对象。如,考虑在程序中引入一个可撤销动作的类:
abstract class UndoableAction(val description:String){
    def undo(): Unit
    def redo():Unit
}
默认情况下可以是“什么都不做”。对于这个行为只需要一个实例即可。
object DoNothingAction extends UndoableAction("Do nothing"){
    override def undo() {}
    override def redo(){}
}
DoNothingAction对象可以被所有需要这个缺省行为的地方公用。
val actions = Map("open" -> DoNothingAction, "save" -> DoNothingAction, ...)//打开和保存功能尚未实现

6.4 apply方法

我们通常会定义和使用对象的apply方法。当遇到如下形式的表达式时,apply方法就会被调用。
        Object(参数1, 参数2, ... , 参数N)
通常,这样的apply方法返回的是伴生类的对象。例如,Array对象定义了apply方法,可以用下面的表达式创建数组:
        Array("Mary", "had", "a", "little", "lamb")
注意:不要把Array(10)和new Array(10)混淆。前一个表达式调用的是apply(10),输出一个单元素(整数10)的Array[Int];而第二个表达式调用的是构造器this(10),结果是Array[Nothing],包含10个null元素。

6.5 应用程序对象

每个Scala程序都必须从一个对象的main方法开始,这个方法的类型为Array[String] => Unit:

object Hello{
    def main(args: Array[String]){
        println("Hello, World!")
    }
}
除了每次都提供自己的main方法外,也可以扩展App特质,然后将程序代码放入构造器方法体内:

object Hello extends App{
    println("Hello, World!")
}
  • 如果需要命令行参数,则可以通过args属性得到:
object Hello extends App{
    if(args.length > 0)
        println("Hello, " + args(0)
    else 
        prinln("Hello, World!")
}
  • 如果在调用该应用程序时设置了scala.time选项的话,程序退出时会显示逝去的时间。
$scalac Hello.scala
$scala -Dscala.time Hello Fred
Hello, Fred
[total 4ms]
App特质扩展自另一个特质DelayedInit,编译器对该特质有特殊处理。所有带有该特质的类,其初始化方法都会被挪到delayedinit方法中。App特制的main方法捕获到命令行参数,调用delayedInit方法,并且还可以根据要求打印出逝去的时间。

6.6 枚举

和Java或C++不同,Scala并没有枚举类型。不过,标准类库提供了一个Enumeration助手类,可以用于产出枚举。

例如,定义一个扩展Enumeration类的对象并以Value方法调用初始化枚举中的所有可选值。

object TrafficLightColor extends Enumeration{
    val Red, Yellow, Green = Value
}

这里定义了三个字段:Red、Yellow、Green,然后用Value调用将它们初始化。得到val Red = Value;val Yellow  = Value; val Green = Value。每次调用Value方法都返回内部类的新实例,该内部类也叫做Value。

记住枚举的类型是TrafficLightColor.Value而不是TrafficLightColor——后者是握有这些值的对象。

object TrafficLightColor extends Enumeration{
    type TrafficLightColor = value      //增加一个类型别名
    val Red, Yellow, Green = Value
}

//现在枚举的类型变成了TrafficLightColor.TrafficLightColor,但仅当使用import语句时这样做才有意义。
import TrafficLightColor._
def doWhat(color: TrafficLightColor) = {
    if(color == Red) "stop"
    else if(color == Yellow) "hurry up"
    else "go"
}

枚举值得ID可通过id方法返回,名称通过toString方法返回。对TrafficLightColor.values的调用输出所有枚举值的集:

for(c -> TrafficLightColor.values) println(c.id + ":" + c)

最后,可以通过枚举的ID或名称来进行查找定位,以下两段代码都输出TrafficLightColor.Red对象:

TrafficLightColor(0)        //调用Enumeration.apply
TrafficLightColor.withName("Red")



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

love666666shen

谢谢您的鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值