官术网_书友最值得收藏!

4.3 單例對(duì)象

正如第1章提到的,Scala比Java更面向?qū)ο蟮囊稽c(diǎn)是,Scala的類不允許有靜態(tài)(static)成員。對(duì)于此類使用場(chǎng)景,Scala提供了單例對(duì)象。單例對(duì)象的定義看上去與類定義很像,只不過class關(guān)鍵字被替換成了object關(guān)鍵字。參考示例4.2。

示例4.2 ChecksumAccumulator類的伴生對(duì)象

在示例4.2中的單例對(duì)象名為ChecksumAccumulator,與前一個(gè)示例中的類名一樣。當(dāng)單例對(duì)象與某個(gè)類共用同一個(gè)名稱時(shí),它被稱作這個(gè)類的伴生對(duì)象companion object)。必須在同一個(gè)源碼文件中定義類和類的伴生對(duì)象。同時(shí),類又叫作這個(gè)單例對(duì)象的伴生類companion class)。類和它的伴生對(duì)象可以互相訪問對(duì)方的私有成員。

ChecksumAccumulator單例對(duì)象有一個(gè)名稱為calculate的方法,用于接收一個(gè)String,并計(jì)算這個(gè)String的所有字符的校驗(yàn)和checksum)。它同樣也有一個(gè)私有的字段,即cache,這是一個(gè)緩存了之前已計(jì)算過的校驗(yàn)和的可變映射。[3]方法的第一行,即“if (cache.contains(s))”,用于檢查緩存以確認(rèn)傳入的字符串是否已經(jīng)被包含在映射中。如果是,就返回映射的值,即cache(s)。如果沒有,則執(zhí)行else子句,計(jì)算校驗(yàn)和。else子句的第一行定義了一個(gè)名稱為accval,用一個(gè)新的ChecksumAccumulator實(shí)例初始化。[4]接下來的一行是一個(gè)for表達(dá)式,遍歷傳入字符串的每一個(gè)字符,通過調(diào)用toByte方法將字符轉(zhuǎn)換成Byte,然后將Byte傳遞給acc指向的ChecksumAccumulator實(shí)例的add方法。[5]for表達(dá)式執(zhí)行完成以后,方法的下一行調(diào)用accchecksum方法,從傳入的String中得到其校驗(yàn)和,保存到名稱為csval。再往下一行,即cache += (s -> cs),將傳入的字符串作為鍵,計(jì)算出的整型的校驗(yàn)和作為值,這組鍵/值對(duì)被添加到緩存映射中。該方法的最后一個(gè)表達(dá)式,即cs,確保了該方法的結(jié)果是這個(gè)校驗(yàn)和。

如果你是Java程序員,則可以把單例對(duì)象當(dāng)作用于安置那些用Java時(shí)打算編寫的靜態(tài)方法。可以用類似的方式訪問單例對(duì)象的方法:?jiǎn)卫龑?duì)象名、英文句點(diǎn)和方法名。例如,可以像這樣調(diào)用ChecksumAccumulator單例對(duì)象的calculate方法:

不過,單例對(duì)象并不僅僅用來存放靜態(tài)方法。它是一等(first-class)的對(duì)象。可以把單例對(duì)象的名稱想象成附加在對(duì)象身上的“名稱標(biāo)簽”:

定義單例對(duì)象并不會(huì)定義類型(在Scala的抽象層級(jí)上是這樣的)。當(dāng)只有ChecksumAccumulator的對(duì)象定義時(shí),并不能定義一個(gè)類型為ChecksumAccumulator的變量。確切地說,名稱為ChecksumAccumulator的類型是由這個(gè)單例對(duì)象的伴生類來定義的。不過,單例對(duì)象可以擴(kuò)展自某個(gè)超類,還可以混入特質(zhì)。你可以通過這些類型來調(diào)用它的方法,用這些類型的變量來引用它,還可以將它傳入那些預(yù)期為這些類型的入?yún)⒌姆椒ㄖ小N覀儗⒃诘?2章給出單例對(duì)象繼承類和特質(zhì)的示例。

類和單例對(duì)象的一個(gè)區(qū)別是單例對(duì)象不接收參數(shù),而類可以。由于無法用new實(shí)例化單例對(duì)象,也就沒有任何手段來向它傳參。每個(gè)單例對(duì)象都是通過一個(gè)靜態(tài)變量引用合成類synthetic class)的實(shí)例來實(shí)現(xiàn)的,因此單例對(duì)象在初始化的語義上與Java的靜態(tài)成員是一致的。[6]尤其體現(xiàn)在,單例對(duì)象在有代碼首次訪問時(shí)才會(huì)被初始化。

不與某個(gè)伴生類共用同一個(gè)名稱的單例對(duì)象叫作獨(dú)立對(duì)象standalone object)。獨(dú)立對(duì)象有很多用途,包括收集相關(guān)的工具方法,或者定義Scala應(yīng)用程序的入口,等等。下一節(jié)將介紹這樣的用法。

主站蜘蛛池模板: 忻城县| 威海市| 和硕县| 沂南县| 乐都县| 宣化县| 桂平市| 盈江县| 台湾省| 大庆市| 滦南县| 兰西县| 高安市| 长子县| 临泉县| 修水县| 横峰县| 社会| 东乌| 灵川县| 仙居县| 平邑县| 精河县| 仙桃市| 康平县| 深水埗区| 峨山| 沂南县| 山东省| 蒲江县| 磐石市| 茂名市| 泊头市| 中方县| 旬阳县| 克东县| 玉林市| 满洲里市| 曲水县| 海兴县| 文水县|