Kotlin中的object關(guān)鍵字
kotlin中object的用法一般有兩種,對(duì)象表達(dá)式 和 對(duì)象聲明
對(duì)象表達(dá)式
所謂表達(dá)式,就是可以賦值的語(yǔ)句。
任何時(shí)候,如果我們只需要“一個(gè)對(duì)象而已”,并不需要一個(gè)類class,那么我們可以簡(jiǎn)單地寫:
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
比如說(shuō)我們?cè)谀承﹫?chǎng)合需要傳入一個(gè)接口類型的對(duì)象,Java中可能會(huì)用到匿名類,Kotlin中則用object處理:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*……*/ }
override fun mouseEntered(e: MouseEvent) { /*……*/ }
})
可以看作是一個(gè)匿名的對(duì)象。
匿名對(duì)象只能在私有方法作用域中返回,用在公有作用域中返回的實(shí)際類型則是該類型的超類,沒(méi)有超類就是Any。在匿名對(duì)象中添加的成員將無(wú)法訪問(wèn)。
class C {
// 私有函數(shù),所以其返回類型是匿名對(duì)象類型
private fun foo() = object {
val x: String = "x"
}
// 公有函數(shù),所以其返回類型是 Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 沒(méi)問(wèn)題
val x2 = publicFoo().x // 錯(cuò)誤:未能解析的引用“x”
}
}
對(duì)象表達(dá)式中的代碼可以訪問(wèn)來(lái)自包含它的作用域的變量。
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
// ……
}
對(duì)象聲明
和Class關(guān)鍵字一樣,用于聲明一個(gè)類,該類自動(dòng)實(shí)現(xiàn)單例模式。不能被賦值。
object Test {
val a = 0;
}
該類字節(jié)碼文件轉(zhuǎn)成Java后如下:
public final class Test {
private static final int a;
@NotNull
public static final Test INSTANCE;
public final int getA() {
return a;
}
private Test() {
}
static {
Test var0 = new Test();
INSTANCE = var0;
}
}
訪問(wèn)的時(shí)候不用像Java一樣getInstance,可以直接Test表示這個(gè)對(duì)象。
注意:對(duì)象聲明不能在局部作用域(即直接嵌套在函數(shù)內(nèi)部),但是它們可以嵌套到其他對(duì)象聲明或非內(nèi)部類中。
伴生對(duì)象
類內(nèi)部的對(duì)象聲明可以用 companion 關(guān)鍵字標(biāo)記:
class Test {
companion object A {
val a = "hello"
fun create() = "內(nèi)部類中的方法"
}
}
這樣做的好處是可以略過(guò)該類部?jī)?nèi)名,直接訪問(wèn)到類中的對(duì)象或方法:
val a = Test.a
val b = Test.create()
這樣一來(lái)這個(gè)對(duì)象聲明的名字就不重要了,所以在Kotlin語(yǔ)法中可以直接省略。(省略后kotlin自動(dòng)將該對(duì)象聲明命名為Companion)
class Test {
companion object {
}
}
val companion = Test.Companion
這種形式的對(duì)象聲明就叫伴生對(duì)象。
通常咱們?cè)谟肒otlin的時(shí)候會(huì)用伴生對(duì)象來(lái)充當(dāng)Java中的靜態(tài)(static),但實(shí)際上它們是有區(qū)別的,用伴生對(duì)象生成的字節(jié)碼轉(zhuǎn)成Java后如下:
| 伴生對(duì)象 | 對(duì)象聲明 | |
|---|---|---|
| Kotlin寫法 | ![]() Kotlin-伴生對(duì)象
|
![]() Kotlin-對(duì)象聲明
|
| 轉(zhuǎn)化成Java | ![]() Java-伴生對(duì)象
|
![]() Java對(duì)象聲明
|
當(dāng)然,在 JVM 平臺(tái),如果使用
@JvmStatic注解,你可以將伴生對(duì)象的成員生成為真正的靜態(tài)方法和字段。更詳細(xì)信息請(qǐng)參見(jiàn)Java 互操作性一節(jié) 。
對(duì)象表達(dá)式和對(duì)象聲明之間的語(yǔ)義差異
對(duì)象表達(dá)式和對(duì)象聲明之間有一個(gè)重要的語(yǔ)義差別:
- 對(duì)象表達(dá)式是在使用他們的地方立即執(zhí)行(及初始化)的;
- 對(duì)象聲明是在第一次被訪問(wèn)到時(shí)延遲初始化的;
- 伴生對(duì)象的初始化是在相應(yīng)的類被加載(解析)時(shí),與 Java 靜態(tài)初始化器的語(yǔ)義相匹配。



