Scala之对象(单例对象,伴生对象,apply方法,应用程序对象和枚举)

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

object Accounts {
  private var lastNumber = 0
  def newUniqueNumber() = { lastNumber += 1;lastNumber}
}

当想要一个新账号时,调用Account.newUniqueNumber()就好。
对象的构造器在该对象第一次被使用时调用,上例中,Account的构造器在Account.newUniqueNumber()首次调用时被执行了,如果一个对象从未被使用,那构造器也不会执行。
对象本质上可以拥有类的所有特性,甚至可以扩展其他类或特质,但唯一不同的是:我们不能提供构造器参数。
在Java中使用单例对象的场景,在scala中我们都可以用对象来实现:
1.作为存放工具函数或常量的地方
2.高效地共享单个不可变实例
3.需要用单个实例来协调某个服务时

2.伴生对象
在Java中,我们通常会用到既有实例方法又有静态方法的类。在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() = {
    lastNumer += 1
    lastNumber
  }
}

类和它的伴生对象可以相互访问私有属性,但它们必须存在于一个源文件中。

3.apply方法
当遇到如下的表达式时,apply方法就会被调用:
Object(参数1,参数2,…,参数N)
通常,这样的一个apply方法返回的是伴生类的对象。
for ex:
Array对象定义了apply方法,使我们可以用下面的表达式来创建数组:
Array(“Mary”,“Jack”,“Rose”,“Jkson”)
为什么不用构造器呢?因为对于嵌套而言,省去new会方便很多,如:
Arrray(Array(1,7),Array(2,9))
需要注意的是,Array(100)和new Array(100)很容易弄混,前一个是apply(100),输出单元素100的Array[Int],而第二个表达式调用的是构造器this(100),结果为Array[Nothing],包含100个null元素。
实例:

class Account private (val id: Int,initialBalance: Double) {
  private var balance = initialBalance
  ...  
}

object Account { //伴生对象
  def apply(initialBalance: Double) = new Account(newUniqueNumber(),initialBalance)
  ...
}

这样你就可以这样构造账号对象:

val acct = Account(1,1000.0)

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

object Hello {
  def main(args: Array[String]){
     println("Hello Scala")
  }
}

除了自己提供main方法外,我们也可以扩展App特质,将main方法放入构造器方法内:

object Hello extends App {
  println("Hello Scala")
}

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

object Hello extends App {
  if (args.length > 0)
  	println(args(0))
  else
  	println("Hello Scala")
}

5.枚举
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,或者可以向Value方法中
传入id,名称:

val Red = Value(0,"Stop")
val Yellow = Value(11)  //名称为“Yellow”
val Green = Value("") //id12

如果不指定,那么id会将前一个枚举值基础上加1,从零开始,缺省名称为字段名。
定义完成后就可以用TrafficLightColor.Red这样来引用枚举值了,想简便一些可以:

import TrafficLightColor._

直接引入枚举值。
需要注意的是,枚举的类型是TrafficLightColor.Value,而不是TrafficLightColor,这个是握有这些值的对象。有人
推荐可以增加一个类型别名:

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

现在枚举的类型变为了TrafficLightColor.TrafficLightColor,但仅当我们使用import语句这样做才有意义
如:

import TrafficLightClor._
def doWhar(color: TrafficLight) = {
  if (color == Red) "Stop"
  else if (color == Yellow) "hurry up"
  else "go"
}

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

for (x <- TrafficLightColor.values) println(x.id + ":" + x.toString)

最后,可以通过枚举的id或名称来进行查找定位,下面两句都输出为TrafficLightColor.Red对象:

TrafficLightColor(0)  //将调用Enumration.apply方法
TrafficLightColor.withName("Red") 
发布了14 篇原创文章 · 获赞 1 · 访问量 684

猜你喜欢

转载自blog.csdn.net/qq_33891419/article/details/103626715