scala之对象

单例对象

  Scala没有静态方法或静态字段,你可以用object这个语法结构来达到同样的目的。对象定义了某个类的单个实例,包含你想要的特性。如,

object Number {
  private var num = 0;

  def newUniqueNum() = {
    num += 1
    num
  }

  def main(args: Array[String]) {
    println(Number.newUniqueNum()) //打印1
  }
}

注:Scala的单例对象和Java中的静态方法/字段调用方式一致。在Scala中,对象的构造器在该对象第一次被使用时调用,若一个对象从未被使用,那么其构造器也不会被执行。对象本质上可以拥有类的所有特性-它甚至可以扩展其它类或特质,但是你不能提供构造器参数。


Scala单例对象使用场景

  1.作为存放工具函数或常量的地方

  2.高效共享单个不可变实例

  3.需要单个实例来协调某个服务时(可参考单例模式)


伴生对象

  在Java或C++中,你通常会用到即有实例方法又有静态方法的类。在Scala中,你可以通过类和与类同名的“伴生”对象来达到同样的目的。如

class Num {
  private val id = Num.newUniqueNum

  private def test() = {}
}

object Num {
  private var num = 0
  new Num().test()
  private def newUniqueNum = {num += 1; num}
}
注:类和它的伴生对象可以相互访问私有特性;它们必须存在于同一个源文件中;类的伴生对象可以被访问,但并不在作用域中,Num类必须通过Num.newUniqueNum而不是直接用newUniqueNum来调用伴生对象的方法。

扩展类或特质的对象

  一个对象可以扩展类以及一个或多个特质,其结果是一个扩展了指定类以及特质的类的对象,同时拥有在对象中给出的所有特性。一个有用的场景是给出可被共享的缺省对象。举例在来说,考虑在程序中引入一个可撤销动作的类,默认情况下什么都不做,对于这个行为你只需要一个实例即可,可通过对象扩展类实现。如下,

//定义供扩展的抽象类
abstract class UndoableAction(val description : String) {
  def undo() : Unit
  def redo() : Unit
}

//DoNthingAction扩展自UndoableAction,默认情况下什么都不做。
object DoNothingAction extends UndoableAction("Do nothing") {
  override  def undo() {}
  override def redo() {}
}

注:DoNothingAction对象可以被所有需要这个缺省行为的地方共用。


apply方法

  我们通常会定义使用对象的apply方法。当遇到如下形式的表达式时,apply方法就会被调用:

                           Object(参数1, ..., 参数N)

通常,这样一个apply方法返回的是伴生类的对象。举例来说,Array对象定义了apply方法,让我们可以用下面这样的表达式来创建数组:

                           Array("a","b","c")

为什么我们不使用构造器呢?对于嵌套表达式而言,省去new关键字会方便很多。如,Array(Array(1,7), Array(2,6))。

  我们来看一个示例:

class Account(val id: Int, initBalance: Double) {
  private var balance = initBalance

  def printTe() = println(balance)
}

object Account {
  def apply(initBalance: Double) = {
    new Account(1, initBalance)
  }
}

object Test {
  def main(args: Array[String]) {
    val account = Account(2.0)
    account.printTe
  }
}
注:输出结果为2.0。


应用程序对象

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

object Test {
  def main(args: Array[String]) {
    println("Hello, World!")
  }
}
注:输出结果为Hello, World!。

  除了每次都提供自己的main方法外,你也可以扩展App特质,然后将程序代码翻入构造器方法体内。如,

object Hello extends App {
  println("Hello, World!")
}
注:输出结果为Hello, World!。

   如果你需要命令行参数,则可以通过args属性得到,如

object Hello extends App {
  if(args.length > 0){
    println("Hello, " + args(0))
  }
  else{
    println("Hello, World!")
  }
}
在类文件目录下执行如下命令

scalac Hello.scala
scala -Dscala.time Hello Ming
注:输出结果为Hello, Ming。如果在你在调用该程序时设置了scala.time选项的话,程序退出时会输出消耗的时间。App特质扩展自另一个特质DelayedInit,编译器对该特质有特殊处理。所有带有该特质的类,其初始化方法都会被挪到delayedInit方法中。App特质的main方法捕获到命令行参数,调用delayedInit方法,并且还可以根据要求打印消耗的时间。

枚举

  和Java或C++不同,Scala并没有枚举类型。但是,标准库提供了一个Enumeration助手类,可以用于产出枚举类。例如,定义一个扩展Enumeration类的对象并以Value方法调用初始化枚举中的所有可选值。示例如下,

object Color extends Enumeration {
  val Red, Yellow, Green = Value //等同于:val Red = Value; val Yellow = Value; val Green = Value;
}

注:上述示例定义了三个字段:Red、Yellow、Green,然后用Value调用将它们初始化。每次调用Value方法都返回内部类的新实例,该内部类也叫做Value。或者你也可以向Value方法传入ID、名称或者两个参数都传。如果不指定,则ID在将前一个枚举值的基础上加一,从零开始。缺省字段名称为字段的名。定义完成后,你就可以用Color.Red、Color.Yellow、Color.Green来引用枚举值了。如果这些变得冗长繁琐,则可以通过import Color._语句直接引入枚举类,然后直接调用Red等字段即可。记住枚举的类型是Color.Value而不是Color,后者是握有这些值的对象。

  完整示例1:

object Color extends Enumeration {
  val Red = Value(0, "Red")
  val Yellow = Value("Yellow")
  val Green = Value("Green")
}

object TestEnum {
  def main(args: Array[String]): Unit = {
    for(color <- Color.values) {
      if(color.id == 2){
        print(color.id + ": " + color)
      }
      else{
        print(color.id + ": " + color + ",")
      }
    }
  }
}
注:输出结果为0: Red,1: Yellow,2: Green。
  完整示例2:

object Color extends Enumeration {
  val Red = Value(0, "Red")
  val Yellow = Value("Yellow")
  val Green = Value("Green")
}

import Color._

object TestEnum {
  def main(args: Array[String]): Unit = {
    for(color <- values) {
      if(color.id == 2){
        print(color.id + ": " + color + ".")
      }
      else{
        print(color.id + ": " + color + ",")
      }
    }
  }
}
注:输出结果为0: Red,1: Yellow,2: Green。上述示例中,你可以直接使用Red、Yellow、Green。
  完整示例3:
object Color extends Enumeration {
  type Color = Value //定义类型别名
  val Red = Value(0, "Red")
  val Yellow = Value("Yellow")
  val Green = Value("Green")
}

import Color._
object action {
  def doWhat(color: Color) = {
    if(color == Red) "stop"
    else if(color == Yellow) "hurry up"
    else "go"
  }
}

object TestEnum {
  def main(args: Array[String]) {
    println(action.doWhat(Color.Green))
  }
}

注:输出结果为go。上述示例中使用type关键字定义类型别名,则该枚举的类型变成了Color.Color。

  完整示例4:

object Color extends Enumeration {
  type Color = Value
  val Red = Value(0, "Red")
  val Yellow = Value("Yellow")
  val Green = Value("Green")
}

object TestEnum {
  def main(args: Array[String]) {
    print(Color(0) + ":" + Color.withName("Yellow"))
  }
}
注:输出结果为Red:Yellow。其中,Color(0)将调用Enumeration.apply。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值