【对比Java学Kotlin】object 关键字
兩種用法
Kotlin 的 object 關鍵字有兩種用法,一個是作為右值表達式的前綴,一個是作為類的前綴修飾符。
object 表達式
object 表達式一般用于對現有類進行稍微修改、因為是臨時使用一次而不值得新建類完成的場景,我們稱其為匿名對象。
Any 類型的匿名對象
先來直觀感受下用法:
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()這時 Java 同學舉手示意要發言:這個我也行呀,你看:
Object o = new Object() {String hello = "Hello";String world = "World";@Overridepublic String toString() {return hello + ", " + world;} };// 還有這種匿名對象: Runnable r = new Runnable() {@Overridepublic void run() {} };r.run();看起來確實挺像的,但是,在 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 中可以正確運行Java:矮油,有點吊哦,我是不允許這種調用的,會直接編譯報錯:
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(); // 編譯報錯:Cannot resolve method 'length' in 'Object'具體類型的匿名對象
可以看出上述 object 表達式是祖先類 Any 的匿名對象。我們不僅可以對 Any,還能對某個具體的類/接口定義匿名對象,具體用法是 object 關鍵字+冒號:
window.addMouseListener(object : MouseAdapter() {override fun mouseClicked(e: MouseEvent) { /*...*/ }override fun mouseEntered(e: MouseEvent) { /*...*/ } })更進一步,可以在定義匿名類的時候同時實現繼承關系:
open class A(x: Int) {public open val y: Int = x }interface B { /*...*/ }val ab: A = object : A(1), B {override val y = 15 }匿名對象做返回值
匿名對象類型除了以普通變量的形式出現,還可以當做函數的返回值:
class C {private fun getObject() = object { // private 方法,所以 printX() 方法可以引用成員變量 xval x: String = "x"}fun printX() {println(getObject().x) // 可以引用到 x} }但是并不是所有場景下都可以引用匿名對象的成員的,如下場景是可以的:
- 當匿名對象是局部變量時;
- 作為成員函數返回值或成員變量出現時,成員需是 private 且不是 inline 的;
當成員不是 private 或者是 inline是,我們無法引用到匿名對象的成員,只會把它當做未進行過修改的類型進行解析,這個類型由成員顯式聲明的類型決定:
閉包
與 Java 中的匿名類一樣,Kotlin 的匿名對象也可以引用到匿名對象外部的變量,從而實現閉包的效果,而且不需要像 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 關鍵字另一種用法是修飾類或者類的成員,但是不能修飾局部變量。其中最常見的是直接修飾類,這時被修飾的類就是個線程安全的單例:
object DataProviderManager {fun registerDataProvider(provider: DataProvider) {// ...}val allDataProviders: Collection<DataProvider>get() = // ... }在 Kotlin 中使用上述單例:
DataProviderManager.registerDataProvider(...)在 Java 中使用上述單例:
DataProviderManager.INSTANCE.registerDataProvider(...)companion 關鍵字
當我們想像 Java static 關鍵字那樣,不借助某個具體實例來引用類的成員方法或屬性時,可以在類里面用 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()需要注意的是:
- 類里面最多只能有一個 companion object;
- 上述例子中的自定義名稱 Company 可以省略,不影響使用,如果省略 Company 則調用的時候可以使用 MyClass.Companion,或者直接使用 MyClass 均可,MyClass 就代指其內部的 companion object;
- 外部類的成員可以引用 companion object 里面的成員;
- companion object 的用法看起來跟 Java 的 static 關鍵字有點像,但是其本質上還是一個對象,上述示例中 Company 實現了 Factory 接口也印證了這一點,如果要用真正的 static 字段,需要使用 @JVMStatic 注解,且 @JVMStatic 注解只能用于 object 或 companion object 修飾的對象的成員;
表達式和聲明的區別
- 表達式在聲明的地方就會被立即初始化和執行;
- 聲明是延遲初始化的,即第一次被使用的時候才會初始化;
總結
以上是生活随笔為你收集整理的【对比Java学Kotlin】object 关键字的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 联想ThinkPad安装windows7
- 下一篇: JavaSE基础(4) JAVA_HOM