【对比Java学Kotlin】object 关键字
兩種用法
Kotlin 的 object 關(guān)鍵字有兩種用法,一個(gè)是作為右值表達(dá)式的前綴,一個(gè)是作為類(lèi)的前綴修飾符。
object 表達(dá)式
object 表達(dá)式一般用于對(duì)現(xiàn)有類(lèi)進(jìn)行稍微修改、因?yàn)槭桥R時(shí)使用一次而不值得新建類(lèi)完成的場(chǎng)景,我們稱(chēng)其為匿名對(duì)象。
Any 類(lèi)型的匿名對(duì)象
先來(lái)直觀(guān)感受下用法:
val o = object {val hello = "Hello"val world = "World"override fun toString(): String {return "$hello, $world"} }val r = object : Runnable {override fun run() {TODO("Not yet implemented")} }r.run()這時(shí) Java 同學(xué)舉手示意要發(fā)言:這個(gè)我也行呀,你看:
Object o = new Object() {String hello = "Hello";String world = "World";@Overridepublic String toString() {return hello + ", " + world;} };// 還有這種匿名對(duì)象: Runnable r = new Runnable() {@Overridepublic void run() {} };r.run();看起來(lái)確實(shí)挺像的,但是,在 Kotlin 中我們可以隨意加其他方法,并能引用到這些方法:
val o = object {val hello = "Hello"val world = "World"override fun toString(): String {return "$hello, $world"}fun length(): Int {return toString().length} }val l = o.length() // 注意此行代碼,在 kotlin 中可以正確運(yùn)行Java:矮油,有點(diǎn)吊哦,我是不允許這種調(diào)用的,會(huì)直接編譯報(bào)錯(cuò):
Object o = new Object() {String hello = "Hello";String world = "World";@Overridepublic String toString() {return hello + ", " + world;}public int length() {return toString().length();} };int l = o.length(); // 編譯報(bào)錯(cuò):Cannot resolve method 'length' in 'Object'具體類(lèi)型的匿名對(duì)象
可以看出上述 object 表達(dá)式是祖先類(lèi) Any 的匿名對(duì)象。我們不僅可以對(duì) Any,還能對(duì)某個(gè)具體的類(lèi)/接口定義匿名對(duì)象,具體用法是 object 關(guān)鍵字+冒號(hào):
window.addMouseListener(object : MouseAdapter() {override fun mouseClicked(e: MouseEvent) { /*...*/ }override fun mouseEntered(e: MouseEvent) { /*...*/ } })更進(jìn)一步,可以在定義匿名類(lèi)的時(shí)候同時(shí)實(shí)現(xiàn)繼承關(guān)系:
open class A(x: Int) {public open val y: Int = x }interface B { /*...*/ }val ab: A = object : A(1), B {override val y = 15 }匿名對(duì)象做返回值
匿名對(duì)象類(lèi)型除了以普通變量的形式出現(xiàn),還可以當(dāng)做函數(shù)的返回值:
class C {private fun getObject() = object { // private 方法,所以 printX() 方法可以引用成員變量 xval x: String = "x"}fun printX() {println(getObject().x) // 可以引用到 x} }但是并不是所有場(chǎng)景下都可以引用匿名對(duì)象的成員的,如下場(chǎng)景是可以的:
- 當(dāng)匿名對(duì)象是局部變量時(shí);
- 作為成員函數(shù)返回值或成員變量出現(xiàn)時(shí),成員需是 private 且不是 inline 的;
當(dāng)成員不是 private 或者是 inline是,我們無(wú)法引用到匿名對(duì)象的成員,只會(huì)把它當(dāng)做未進(jìn)行過(guò)修改的類(lèi)型進(jìn)行解析,這個(gè)類(lèi)型由成員顯式聲明的類(lèi)型決定:
閉包
與 Java 中的匿名類(lèi)一樣,Kotlin 的匿名對(duì)象也可以引用到匿名對(duì)象外部的變量,從而實(shí)現(xiàn)閉包的效果,而且不需要像 Java 那樣外部變量必須是 final 的:
fun countClicks(window: JComponent) {var clickCount = 0var enterCount = 0window.addMouseListener(object : MouseAdapter() {override fun mouseClicked(e: MouseEvent) {clickCount++}override fun mouseEntered(e: MouseEvent) {enterCount++}})// ... }object 聲明
object 關(guān)鍵字另一種用法是修飾類(lèi)或者類(lèi)的成員,但是不能修飾局部變量。其中最常見(jiàn)的是直接修飾類(lèi),這時(shí)被修飾的類(lèi)就是個(gè)線(xiàn)程安全的單例:
object DataProviderManager {fun registerDataProvider(provider: DataProvider) {// ...}val allDataProviders: Collection<DataProvider>get() = // ... }在 Kotlin 中使用上述單例:
DataProviderManager.registerDataProvider(...)在 Java 中使用上述單例:
DataProviderManager.INSTANCE.registerDataProvider(...)companion 關(guān)鍵字
當(dāng)我們想像 Java static 關(guān)鍵字那樣,不借助某個(gè)具體實(shí)例來(lái)引用類(lèi)的成員方法或?qū)傩詴r(shí),可以在類(lèi)里面用 companion object:
interface Factory<T> {fun create(): T}class MyClass {companion object Company : Factory<MyClass> {override fun create(): MyClass = MyClass()}}val f: Factory<MyClass> = MyClassf.create()val f1: Factory<MyClass> = MyClass.Companyf1.create()需要注意的是:
- 類(lèi)里面最多只能有一個(gè) companion object;
- 上述例子中的自定義名稱(chēng) Company 可以省略,不影響使用,如果省略 Company 則調(diào)用的時(shí)候可以使用 MyClass.Companion,或者直接使用 MyClass 均可,MyClass 就代指其內(nèi)部的 companion object;
- 外部類(lèi)的成員可以引用 companion object 里面的成員;
- companion object 的用法看起來(lái)跟 Java 的 static 關(guān)鍵字有點(diǎn)像,但是其本質(zhì)上還是一個(gè)對(duì)象,上述示例中 Company 實(shí)現(xiàn)了 Factory 接口也印證了這一點(diǎn),如果要用真正的 static 字段,需要使用 @JVMStatic 注解,且 @JVMStatic 注解只能用于 object 或 companion object 修飾的對(duì)象的成員;
表達(dá)式和聲明的區(qū)別
- 表達(dá)式在聲明的地方就會(huì)被立即初始化和執(zhí)行;
- 聲明是延遲初始化的,即第一次被使用的時(shí)候才會(huì)初始化;
總結(jié)
以上是生活随笔為你收集整理的【对比Java学Kotlin】object 关键字的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 联想ThinkPad安装windows7
- 下一篇: [教你做小游戏] 用86行代码写一个联机