轉向Kotlin——物件

Android機動車發表於2018-08-06

由於Kotlin中沒有靜態成員的概念,因此Kotlin推出了一個有趣的語法糖:物件。那麼物件能取代靜態類成員嗎?該怎麼做呢?下面會詳細介紹到。

物件表示式

在Java中又匿名類的概念,也就是說,在建立類的時候,無需指定類的名字。匿名類一般用於方法引數。基本理念就是方法需要接收一個類或者介面的例項,而這個例項只是在該方法中使用,沒有必要單獨再定義一個類,或者建立一個物件變數。因此,就在傳入方法引數值的同時建立了該類的例項。程式碼例子如下:

public class JClass {

    public void fun(){
        System.out.println("jclass");
    }
}
複製程式碼
public class JClassTest {

    public static void process(JClass jClass) {
        jClass.fun();
    }

    public static void main(String[] agrs) {
        process(new JClass() {
            @Override
            public void fun() {
                System.out.println("haha jclass");
            }
        });
    }

}
複製程式碼

最終輸出 haha jclass

在Kotlin中也有類似的功能,但不是匿名類,而是物件。與上面程式碼相同功能,下面是Kotlin程式碼:

object JClassTest {

    fun process(jClass: JClass) {
        jClass.`fun`()
    }

    @JvmStatic
    fun main(agrs: Array<String>) {
        process(object : JClass() {
            override fun `fun`() {
                println("haha jclass")
            }
        })
    }

}
複製程式碼

可以看到,要想建立一個物件,就要使用object關鍵字,該對物件要繼承的類需要與object之間用冒號(:)分隔。

物件和類一樣,只能有一個父類,但可以實現多個介面,下面的程式碼中,物件不僅繼承了JClass類,還實現了JInterface介面:

process(object : JClass(), JInterface {
	override fun printlnData() {
		println("haha jinterface")
	}

	override fun `fun`() {
		println("haha jclass")
	}
})
複製程式碼

如果只想建立一個物件,不想繼承任何類,也不想實現任何介面,可以按下面的方式建立:

var data = object {
	var value: String = "H"
}
複製程式碼

宣告匿名物件

匿名物件只能用在本地(函式)或private宣告中。如果將匿名物件用於public函式的返回值,或者public屬性的型別,那麼Kotlin編譯器會將這些函式或屬性的返回型別重新定義為匿名物件的夫型別,如果匿名物件沒有繼承任何類,也沒有實現任何介面,那麼父型別就是Any。因此,新增在匿名物件中的任何成員都將無法訪問。

class ObjectClass {
    // private函式,返回型別是匿名物件本身,可以訪問x
    private fun foo() = object {
        var x = 1
    }

    // public函式,由於匿名物件沒有任何父型別,因此函式的返回型別是Any
    public fun publicFoo() = object {
        var x = 2
    }

    fun bar() {
        var x = foo().x //可以訪問
//        var x2 = publicFoo().x // 編譯錯誤,publicFoo返回的是Any物件
    }
}
複製程式碼

訪問封閉作用域內的變數

在Java中,匿名物件訪問封閉作用域內的變數,需要用final宣告該變數,這也就意味著在匿名物件中無法修改封閉作用域內變數的值。在Java8中,如果只是使用封閉作用域內的變數,該比那輛無需使用final,但一旦修改變數的值,就必須使用final進行修飾,其實在Java8中,,封閉作用域的變數是一個隱式的final變數。

但是在Kotlin中,在匿名物件中就可以任意訪問封閉作用域內的變數,包括修改它的值:

    fun main(agrs: Array<String>) {
        var n = 10
        process(object : JClass(), JInterface {
            override fun printlnData() {
                println("$n")
                println(n++)
            }
        })
    }
複製程式碼

陪伴物件

在Kotlin中並沒有靜態類成員的概念,但並不等於不能實現類似於靜態類成員的功能。陪伴物件就是Kotlin中用來解決這個問題的語法糖。

如果在Kotlin類中定義物件,那麼就稱這個物件為該類的陪伴物件。陪伴物件要使用companion關鍵字宣告:

class CompanionClass {

    companion object {
        val TAG = "JIA"

        fun create(): CompanionClass = CompanionClass()
    }

}
複製程式碼

陪伴物件中定義的成員是可以直接通過類名訪問的。

var instance=CompanionClass.create()
複製程式碼

注意,雖然陪伴物件的成員看起來很像其他語言中的類的靜態成員,但在執行期間,這些成員任然是真實物件的例項的成員,它們與靜態成員是不同的。不過使用@Jvmtatic進行註釋,Kotlin編譯器會將其編譯成Byte Code真正的靜態方法。這些內容以後會詳細介紹。

更多精彩內容,歡迎關注我的微信公眾號——Android機動車

轉向Kotlin——物件

相關文章