美文网首页
Kotlin学习之与Java的互操作

Kotlin学习之与Java的互操作

作者: James999 | 来源:发表于2020-04-03 16:26 被阅读0次

    在 Kotlin 中调用 Java 代码

    Kotlin 在设计时就考虑了 Java 互操作性。可以从 Kotlin 中自然地调用现存的 Java 代码,并且在 Java
    代码中也可以很顺利地调用 Kotlin 代码。
    几乎所有 Java 代码都可以使用而没有任何问题:

    import java.util.*
    fun demo(source: List<Int>) {
            val list = ArrayList<Int>()
            // “for”-循环用于 Java 集合:
            for (item in source) {
                list.add(item)
            }
            // 操作符约定同样有效:
            for (i in 0..source.size - 1) {
                list[i] = source[i] // 调用 get 和 set
            }
    }
    

    Getter 和 Setter

    遵循 Java 约定的 getter 和 setter 的方法(名称以 get 开头的无参数方法和以 set 开头的单参数方
    法)在 Kotlin 中表示为属性。 Boolean 访问器方法(其中 getter 的名称以 is 开头而 setter 的名称以
    set 开头)会表示为与 getter 方法具有相同名称的属性。 例如:

        fun calendarDemo() {
            val calendar = Calendar.getInstance()
            if (calendar.firstDayOfWeek == Calendar.SUNDAY) {
                calendar.firstDayOfWeek = Calendar.MONDAY
            }
            if (!calendar.isLenient) {
                calendar.isLenient = true
            }
            println("calendar = $calendar")
        }
    

    返回 void 的方法

    Java 中调用 Kotlin

    Java 可以轻松调用 Kotlin 代码。 例如,可以在 Java 方法中无缝创建与操作 Kotlin 类的实例。 然而,在
    将 Kotlin 代码集成到 Java 中时, 需要注意 Java 与 Kotlin 之间的一些差异。

    将 Kotlin 中是关键字的 Java 标识符进行转义

    一些 Kotlin 关键字在 Java 中是有效标识符: in、 object、 is 等等。 如果一个 Java 库使用了 Kotlin
    关键字作为方法,你仍然可以通过反引号(`)字符转义它来调用该方法:

    foo.`is`(bar)
    

    空安全与平台类型

    Java 中的任何引用都可能是 null,这使得 Kotlin 对来自 Java 的对象要求严格空安全是不现实的。
    Java 声明的类型在 Kotlin 中会被特别对待并称为平台类型。对这种类型的空检测会放宽, 因此它们的
    安全保证与在 Java 中相同

    val list = ArrayList<String>() // 非空(构造函数结果)
    list.add("Item")
    val size = list.size // 非空(原生 int)
    val item = list[0] // 推断为平台类型(普通 Java 对象)
    

    平台类型表示法

    可空性注解

    注解类型参数

    JSR-305 支持

    已映射类型

    这样的类型不是“按原样”从 Java 加载,而是 映射 到相应的 Kotlin
    类型。 映射只发生在编译期间,运行时表示保持不变。 Java 的原生类型映射到相应的 Kotlin 类型(请记
    住平台类型):

    Java 类型 Kotlin 类型
    byte          kotlin.Byte
    short         kotlin.Short
    int             kotlin.Int
    long          kotlin.Long
    char          kotlin.Char
    float          kotlin.Float
    double      kotlin.Double
    boolean    kotlin.Boolean
    

    Kotlin 中的 Java 泛型

    Java 数组

    Java 可变参数

    Java 类有时声明一个具有可变数量参数(varargs)的方法来使用索引:

    操作符

    受检异常

    Kotlin 特殊处理一部分 Java 类型。

    对象方法

    当 Java 类型导入到 Kotlin 中时,类型 java.lang.Object 的所有引用都成了 Any 。 而因为 Any
    不是平台指定的,它只声明了 toString() 、 hashCode() 和 equals() 作为其成员, 所以为了能
    用到 java.lang.Object 的其他成员,Kotlin 要用到扩展函数

    wait()/notify()

    类型 Any 的引用没有提供 wait() 与 notify() 方法。
    通常不鼓励使用它们,而建议使用
    java.util.concurrent 。 如果确实需要调用这两个方法的话,那么可以将引用转换为
    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 { ...... }
    }
    

    不要忘记《Effective Java》第三版 的第 13 条: 谨慎地改写clone。

    finalize()

    要覆盖 finalize() ,所有你需要做的就是简单地声明它,而不需要 override 关键字:

    class C {
         protected fun finalize() {
              // 终止化逻辑
        }
    }
    

    根据 Java 的规则,finalize() 不能是 private 的

    从 Java 类继承

    在 kotlin 中,类的超类中最多只能有一个 Java 类(以及按你所需的多个 Java 接口)。

    访问静态成员

    Java 类的静态成员会形成该类的“伴生对象”。我们无法将这样的“伴生对象”作为值来传递, 但可以显
    式访问其成员,例如:

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

    要访问已映射到 Kotlin 类型的 Java 类型的静态成员,请使用 Java 类型的完整限定
    名: java.lang.Integer.bitCount(foo) 。

    Java 反射

    Java 反射适用于 Kotlin 类,反之亦然。如上所述,你可以使用 instance::class.java , ClassName::class.java 或者 instance.javaClass 通过 java.lang.Class 来进入 Java
    反射。
    其他支持的情况包括为一个 Kotlin 属性获取一个 Java 的 getter/setter 方法或者幕后字段、为一个
    Java 字段获取一个 KProperty 、为一个 KFunction 获取一个 Java 方法或者构造函数,反之亦然。

    SAM 转换

    在 Kotlin 中使用 JNI

    Java 中调用 Kotlin

    属性

    包级函数

    实例字段

    静态字段

    在具名对象或伴生对象中声明的 Kotlin 属性会在该具名对象或包含伴生对象的类中具有静态幕后字
    段。
    通常这些字段是私有的,但可以通过以下方式之一暴露出来:

    • @JvmField 注解;
    • lateinit 修饰符;
    • const 修饰符。
      使用 @JvmField 标注这样的属性使其成为与属性本身具有相同可⻅性的静态字段。
    class Key(val value: Int) {
        companion object {
            @JvmField
            val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value }
        }
    }
    //
    // Java
    Key.COMPARATOR.compare(key1, key2);
    // Key 类中的 public static final 字段
    

    在具名对象或者伴生对象中的一个延迟初始化的属性具有与属性 setter 相同可⻅性的静态幕后字段。

    object Singleton {
        lateinit var provider: Provider
    }
    
    // Java
    Singleton.provider = new Provider();
    // 在 Singleton 类中的 public static 非-final 字段
    

    (在类中以及在顶层)以 const 声明的属性在 Java 中会成为静态字段:

    // 文件 example.kt
    object Obj {
        const val CONST = 1
    }
    class C {
        companion object {
            const val VERSION = 9
        }
    }
    const val MAX = 239
    
    //在 Java 中:
    int const = Obj.CONST;
    int max = ExampleKt.MAX;
    int version = C.VERSION;
    

    静态方法

    如上所述,Kotlin 将包级函数表示为静态方法。 Kotlin 还可以为具名对象或伴生对象中定义的函数生成
    静态方法,如果你将这些函数标注为 @JvmStatic 的话。 如果你使用该注解,编译器既会在相应对象的
    类中生成静态方法,也会在对象自身中生成实例方法。 例如:

    class C {
        companion object {
            @JvmStatic fun callStatic() {}
            fun callNonStatic() {}
        }
    }
    

    现在,callStatic() 在 Java 中是静态的,而 callNonStatic() 不是:

    C.callStatic(); // 没问题
    C.callNonStatic(); // 错误:不是一个静态方法
    C.Companion.callStatic(); // 保留实例方法
    C.Companion.callNonStatic(); // 唯一的工作方式
    

    对于具名对象也同样:

    object Obj {
        @JvmStatic fun callStatic() {}
        fun callNonStatic() {}
    }
    

    在 Java 中:

    Obj.callStatic(); // 没问题
    Obj.callNonStatic(); // 错误
    Obj.INSTANCE.callNonStatic(); // 没问题,通过单例实例调用
    Obj.INSTANCE.callStatic(); // 也没问题
    

    自 Kotlin 1.3 起,@JvmStatic 也适用于在接口的伴生对象中定义的函数。 这类函数会编译为接口中
    的静态方法。请注意,接口中的静态方法是 Java 1.8 中引入的, 因此请确保使用相应的编译目标。

    interface ChatBot {
        companion object {
            @JvmStatic fun greet(username: String) {
                println("Hello, $username")
            }
        }
    }
    

    接口中的默认方法

    可⻅性

    KClass

    用 @JvmName 解决签名冲突

    生成重载

    受检异常

    空安全性

    型变的泛型

    Nothing 类型翻译

    相关文章

      网友评论

          本文标题:Kotlin学习之与Java的互操作

          本文链接:https://www.haomeiwen.com/subject/bpuouhtx.html