4.1 Java語言和Kotlin語言對比(3)

Java 變長參數varargs

Java類有一些方法定義時會使用不定長度的參數

public class JavaArrayExample {

    public void removeIndicesVarArg(int... indices) {
        // code here...
    }
}

在這種情況下,需要使用擴展操作符(*)來傳遞參數IntArray

val javaObj = JavaArrayExample()
val array = intArrayOf(0, 1, 2, 3)
javaObj.removeIndicesVarArg(*array)

目前無法給一個變長參數的函數傳遞null

操作符

Java無法對函數標記和操作,也就無法使用操作符語法。Kotlin允許使用任何Java方法(函數名和簽名正確即可)當做操作符負載operator overloads。使用內置的語法調用Java函數是不支持的。

強制檢查異常 Checked Exception

在Kotlin中所有的異常都是非強制檢查的,編譯器不會強制要求捕獲任何異常。因此,當調用一個定義了強制檢查的異常的Java方法的時候,Kotlin不會強制你做任何事情。

fun render(list: List<*>, to: Appendable) {
    for (item in list) {
        to.append(item.toString()) // Java would require us to catch IOException here
    }
}

對象方法

當Java類型移植到Kotlin的時候,所有java.lang.Object類型的引用,都被轉換成Any。 因此Any 是平臺無關的,它僅定義了toString(), hashCode() and equals() 這幾個方法,當想要使用java.lang.Object類的其他方法時,Kotlin需要使用方法擴展

wait()/notify()

Effective Java 第69項建議使用併發工具而不使用wait()notify()。因此這些方法在Any類型的引用中並不存在。如果你真的需要調用他們,可以把他強轉成java.lang.Object類型,再使用。

(foo as java.lang.Object).wait()

getClass()

想要獲取Java 的類對象,可以在一個類引用上調用java擴展屬性

val fooClass = foo::class.java

上面的代碼還可以使用Kotlin 1.1 中引入的新特性綁定類引用,可以使用javaClass擴展屬性。

val fooClass = foo.javaClass

clone()

想要複寫clone()方法,你的類必須繼承kotlin.Cloneable

class Example : Cloneable {
    override fun clone(): Any { ... }
}

finalize()

想要複寫finalize()方法,要做的就是簡單地定義它,不需要使用override關鍵字

class C {
    protected fun finalize() {
        // finalization logic
    }
}

根據Java規則,finalize()不能是私有的

從Java類集成

Kotlint中的類,可以繼承最多一個Java類和任意多個接口。

訪問靜態成員

Java類的靜態成員轉換成了’companion objects’ ,不能傳遞’companion objects’,但是可以直接訪問

if (Character.isLetter(a)) {
    // ...
}

Java反射

Java反射可以用在kotlin上,反過來也可以。可以通過使用instance::class.java, ClassName::class.java 或者instance.javaClass 來使用java反射
其他支持行爲包括獲取一個Java 的getter/setter方法,或者支持一個Kotlin屬性,KProperty 對應一個Java 成員變量,KFuntion對應一個Java方法或者構造函數,反過來也可以對應。

SAM 規範(Single Abstract Method)

和Java 8 一樣,Kotlin也支持SAM 規範。這意味着Kotlin函數可以被自動轉換成一個帶有單一默認函數的Java接口的實現,只要接口的參數類型和Kotlin函數的參數類型匹配就行。
可以這樣創建一個SAM 接口的實例

val runnable = Runnable { println("This runs in a runnable") }

在方法中調用,可以這樣

val executor = ThreadPoolExecutor()
// Java signature: void execute(Runnable command)
executor.execute { println("This runs in a thread pool") }

如果Java累有多個方法接受函數式接口,你可以通過使用一個適配函數來把一個lambda轉換成一個特定的SAM 類型,來選擇一個你需要調用的接口。哪些適配函數也可以在需要的時候被編譯器生成。

executor.execute(Runnable { println("This runs in a thread pool") })

注意,SAM 規範僅適用於接口,不適用於抽象類,甚至哪些僅包含了單一函數的抽象類。
還有要注意的是,這個特性僅是爲了Java,因爲Kotlin有合適的函數類型,自動把函數轉換成Kotlin接口的實現是不必要的,因此也沒有支持該操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章