Scala 類(lèi)和對(duì)象 (二)

2018-09-28 18:15 更新

類(lèi)和對(duì)象 (二)

前面提到 Scala 比 Java 更加面向?qū)ο螅@是因?yàn)?Scala 不允許類(lèi)保護(hù)靜態(tài)元素(靜態(tài)變量或靜態(tài)方法)。在 Scala 中提供類(lèi)似功能的是成為“Singleton(單例對(duì)象)”的對(duì)象。在 Scala 中定義 Singleton 對(duì)象的方法除了使用 object,而非 class 關(guān)鍵字外和類(lèi)定義非常類(lèi)似,下面例子創(chuàng)建一個(gè) ChecksumAccumulator 對(duì)象:

object ChecksumAccumulator {
   private val cache = Map [String, Int] ()
   def calculate(s:String) : Int =
      if(cache.contains(s))
         cache(s)
      else {
         val acc=new ChecksumAccumulator
         for( c <- s)
            acc.add(c.toByte)
         val cs=acc.checksum()
         cache += ( s -> cs)
         cs
       }
}

這個(gè)對(duì)象和上一篇?jiǎng)?chuàng)建的類(lèi) ChecksumAccumulator 同名,這在 Scala 中把這個(gè)對(duì)象成為其同名的類(lèi)的“伴侶”對(duì)象( Companion object )。 如果你需要定義的類(lèi)的 companion 對(duì)象,Scala 要求你把這兩個(gè)定義放在同一個(gè)文件中。類(lèi)和其 companion 對(duì)象可以互相訪問(wèn)對(duì)方的私有成員。

如果你是 Java 成員,可以把 Singleton 對(duì)象看成以前 Java 定義靜態(tài)成員的地方。你可以使用類(lèi)似 Java 靜態(tài)方法的方式調(diào)用 Singleton 對(duì)象的方法,比如下面為這個(gè)例子完整的代碼:

import scala.collection.mutable.Map
class ChecksumAccumulator{
   private var sum=0
   def add(b:Byte) :Unit = sum +=b
   def checksum() : Int = ~ (sum & 0xFF) +1
}

object ChecksumAccumulator {
   private val cache = Map [String, Int] ()
   def calculate(s:String) : Int =
      if(cache.contains(s))
         cache(s)
      else {
         val acc=new ChecksumAccumulator
         for( c <- s)
            acc.add(c.toByte)
         val cs=acc.checksum()
         cache += ( s -> cs)
         cs
       }
}

println ( ChecksumAccumulator.calculate("Welcome to Scala Chinese community"))

Scala 的 singleton 對(duì)象不僅限于作為靜態(tài)對(duì)象的容器,它在 Scala 中也是頭等公民,但僅僅定義 Singleton 對(duì)象本身不會(huì)創(chuàng)建一個(gè)新的類(lèi)型,你不可以使用 new 再創(chuàng)建一個(gè)新的 Singleton 對(duì)象(這也是 Singleton 名字的由來(lái)),此外和類(lèi)定義不同的是,singleton 對(duì)象不可以帶參數(shù)(類(lèi)定義參數(shù)將在后面文章介紹)。

回過(guò)頭來(lái)看看我們的第一個(gè)例子 “Hello World“。

object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}

這是一個(gè)最簡(jiǎn)單的 Scala 程序,HelloWorld 是一個(gè) Singleton 對(duì)象,它包含一個(gè) main 方法(可以支持命令行參數(shù)),和 Java 類(lèi)似,Scala 中任何 Singleto 對(duì)象,如果包含 main 方法,都可以作為應(yīng)用的入口點(diǎn)。

在這里要說(shuō)明一點(diǎn)的是,在 Scala 中不要求 public 類(lèi)定義和其文件名同名,不過(guò)使用和 public 類(lèi)和文件同名還是有它的優(yōu)點(diǎn)的,你可以根據(jù)個(gè)人喜好決定是否遵循 Java 文件命名風(fēng)格。

最后提一下 Scala 的 trait 功能,Scala 的 trait 和 Java 的 Interface 相比,可以有方法的實(shí)現(xiàn)(這點(diǎn)有點(diǎn)像抽象類(lèi),但如果是抽象類(lèi),就不會(huì)允許繼承多個(gè)抽象類(lèi))。Scala 的 Trait 支持類(lèi)和 Singleton 對(duì)象和多個(gè) Trait 混合(使用來(lái)自這些 Trait 中的方法,而不時(shí)不違反單一繼承的原則)。

Scala 為 Singleton 對(duì)象的 main 定義了一個(gè) App trait 類(lèi)型,因此上面的例子可以簡(jiǎn)化為:

object HelloWorld extends App{
   println("Hello, world!")
}

這段代碼就不能作為腳本運(yùn)行,Scala 的腳本要求代碼最后以表達(dá)式結(jié)束。因此運(yùn)行這段代碼,需要先編譯這段代碼:

scalac Helloworld.scala

編譯好之后,運(yùn)行該應(yīng)用

scala HelloWord

注意: Scala 提供了一個(gè)快速編譯代碼的輔助命令 fsc (fast scala compliler) ,使用這個(gè)命令,只在第一次使用 fsc時(shí)啟動(dòng) JVM,之后 fsc 在后臺(tái)運(yùn)行,這樣就避免每次使用 scalac 時(shí)都要載入相關(guān)庫(kù)文件,從而提高編譯速度。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)