Scala 篇
單例對象
在 Java 中實現(xiàn)單例對象通常需要自己實現(xiàn)一個類并創(chuàng)建 getInstance()
的方法然后在該方法里使用兩次同步塊或者使用更為優(yōu)雅的基于 enum
的方式。而 Scala 中則更加簡單汉操,只要使用 object
聲明就能創(chuàng)建一個單例對象投队。實際上之前我們創(chuàng)建的擁有 main()
方法的都是單例對象合陵。
object Singleton {
private var num = 0
def sequence() = {
num += 1
num
}
}
在方法的章節(jié)我們已經(jīng)知道了在 Scala 中是沒有靜態(tài)成員這一說的烛缔,但是有時我們可能又真的需要有這種機制灰殴。Scala 就是采用了使用單例對象來實現(xiàn)類似的靜態(tài)成員霉咨。
例:
assert(1 == Singleton.sequence())
assert(2 == Singleton.sequence())
assert(3 == Singleton.sequence())
可以看到這種方式和在 Java 中調(diào)用靜態(tài)方法一模一樣污秆,但是 Scala 中這其實是調(diào)用了一個對象的方法。
通常來說墅茉,Scala 中的單例對象一般用于提供常量及共享不可變對象命黔。
伴生對象
我們知道使用 class
可以創(chuàng)建一個類,使用 object
可以創(chuàng)建一個單例對象就斤,而類和單例對象是可以重名的悍募,此時我們稱該單例對象為此類的伴生對象。
伴生對象有以下特點
- 伴生對象可以用于讓一個類即擁有實例化方法又有靜態(tài)方法洋机。
- 伴生對象可以用于創(chuàng)建同名類的實例坠宴。
- 伴生對象必須與同名類位于同一源文件中。
- 伴生對象與類可以互相訪問各自的私有成員绷旗。
例:
創(chuàng)建一個類
class Companion(private var balance: Int = 0) {
val id = Companion.sequence()
}
創(chuàng)建該類的伴生對象
object Companion {
private var num = 0
def getInfo(account: Companion): String = {
"Balance is " + account.balance
}
private def sequence(): Int = {
num += 1
num
}
def apply(initBalance: Int) = {
new Companion(initBalance)
}
}
使用類與伴生對象
// 通過伴生對象的 apply() 方法創(chuàng)建類的實例
val account = Companion(30)
// 在類中調(diào)用伴生對象的私有方法
assert(1 == account.id)
// 在伴生對象中訪問類的私有屬性
assert("Balance is 30" == Companion.getInfo(account))
繼承
單例對象不能繼承另一個單例對象喜鼓,但是單例對象本身可以繼承另一個類,從而擴展該類的功能衔肢,實現(xiàn)該類的可共享的默認對象
例:
abstract class UndoableAction(val description: String) {
def undo
def redo
}
object DoNothing extends UndoableAction("Do nothing") {
override def undo: Unit = {
println("undo")
}
override def redo: Unit = {
println("redo")
}
}
以上 DoNothing
繼承了 UndoableAction
類颠通,可以用于作為 UndoableAction
的一個默認對象來使用。
應用程序對象
應用程序對象是繼承類 App
的單例對象膀懈,該對象是一個應用程序的入口顿锰,可以通過 args
獲得命令行參數(shù)。即使用了應用程序對象后你就不需要顯示聲明 main()
方法了启搂,應用程序對象中定義的所有語句都會在 main()
方法中執(zhí)行硼控。
例:
object Hello extends App {
println("Hello World")
if (args.length > 0) {
println("The passed arguments are " + args)
} else {
println("There is no argument passed.")
}
}
Kotlin 篇
Object
Kotlin 中的 Object 用法類似 Scala,但與 Scala 中的 Object 的最大區(qū)別是 Kotlin 不允許 Object 和類同名胳赌。
單例對象
例:
object Singleton {
private var num = 0
fun sequence(): Int {
num += 1
return num
}
}
同 Scala 一樣牢撼,Kotlin 也通過 Object 來實現(xiàn)靜態(tài)方法的功能。
例:
assert(1 == Singleton.sequence())
assert(2 == Singleton.sequence())
assert(3 == Singleton.sequence())
伴生對象
伴生對象的概念與 Scala 基本一致疑苫,但是 Kotlin 的伴生對象是通過關鍵字 companion object
定義在類中熏版,而不是類外,伴生對象不與類同名捍掺。
例:
創(chuàng)建類和伴生對象
class Companion(private var balance: Int = 0) {
// Access private method of companion object
val id = Companion.sequence()
companion object Factory {
private var num = 0
fun getInfo(account: Companion): String {
return "Balance is " + account.balance
}
fun create(initBalance: Int): Companion {
return Companion(initBalance)
}
private fun sequence(): Int {
num += 1
return num
}
}
}
使用類與伴生對象
// 通過伴生對象的方法創(chuàng)建類的實例
val account = Companion.create(30)
// 在類中調(diào)用伴生對象的私有方法
assert(1 == account.id)
// 在伴生對象中訪問類的私有屬性
assert("Balance is 30" == Companion.getInfo(account))
object 表達式
object 表達式用于擴展類的功能撼短,使用時類似 Java 中的匿名內(nèi)部類。
例:
定義一個類和接口
open class A(x: Int) {
public open val y: Int = x
}
interface B {
fun info()
}
使用 object 表達式擴展類和接口
val ab = object : A(1), B {
override fun info() {
println("info")
}
override val y: Int
get() = 15
}
println(ab.y)
println(ab.javaClass)
以上示例本質上是生成了一個實現(xiàn)類和接口的匿名內(nèi)部類的對象挺勿。在 Kotlin 中也可以不指定任何父類曲横,直接產(chǎn)生匿名內(nèi)部類:
val obj = object {
val x = 10
val y = 20
}
println(obj.x)
println(obj.javaClass)
總結
- Scala 和 Kotlin 使用單例對象來提供其它語言中的全局常量和靜態(tài)方法的特性
- Scala 的伴生對象與類同名且平級,Kotlin 的伴生對象定義在類中且不同名
- Kotlin 的 object 表達式可以實現(xiàn)簡單的繼承功能
文章源碼見 https://github.com/SidneyXu/JGSK 倉庫的 scala/_18_object
和 kotlin/_18_object
小節(jié)