美文网首页Kotlin学习之路
Kotlin基本语法之(九)Kotlin与java互操作

Kotlin基本语法之(九)Kotlin与java互操作

作者: wanderingGuy | 来源:发表于2019-05-31 10:42 被阅读0次

    实际开发我们即使决定切换到Kotlin语言,但由于历史模块或依赖的第三方库仍是使用Java开发的,这也就不可避免在二者之前产生相互调用,虽然官方宣称100%兼容,但实际使用过程中仍有一些小问题需要注意。

    Kotlin调用Java

    get/set方法

    由于Kotlin中并不需要显式的声明get/set方法,所以对于访问Java标准实体类中的属性,可直接通过属性名称。

    Animal.java
    public class Animal {
        private int age;
        private String name;
    
        public Animal(int age, String name) {
            this.age = age;
            this.name = name;
        }
        //...getter/setter
    }
    

    kotlin中这样使用

    val animal = Animal(3, "twodog")
    println(animal.age)//读取
    animal.name = "dahuang"//修改
    

    获取Java类型

    若想获取某个java类的类型需通过Kotlin的反射实现。::得到Kotlin类型,继续调用扩展属性java得到其对应的java类型。

    val animal = Animal(3, "twodog")
    println(animal::class.java.simpleName)
    //输出
    Animal
    

    wait/notify

    我们知道kotlin中Any与Java中的Object对应,但问题是Any类中只有equals/hashCode/toString三个方法。

    public open class Any {
    
        public open operator fun equals(other: Any?): Boolean
    
        public open fun hashCode(): Int
    
        public open fun toString(): String
    }
    

    那并发编程用到的等待唤醒wait/notify方法如何使用呢?事实上官方不建议使用普通对象锁,取而代之的是Lock锁。如果你确实想使用可以通过下面的方法。

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

    即先强转为java的Object类型,再使用并发函数。

    Java调用Kotlin

    get/set方法

    java访问Kotlin的属性应使用对用的getter/setter方法。

    //Client.kt
    data class Client(var name: String)
    
    //java test
    Client client = new Client("zhangsan");
    System.out.println(client.getName());
    client.setName("lisi");
    

    另外,Kotlin中默认会给属性添加getter/setter方法(val类型的没有setter),这势必会造成一定的性能损耗,可为属性添加@JvmField注解去掉此默认行为。

    //去掉NO属性的getter/setter
    data class Client(var name: String,@JvmField  var NO: Int) 
    

    顶级函数

    之前章节讲到顶级函数是用静态方法实现的,而该静态方法所在的类为kotlin文件名+Kt。

    // TestPackageMethod.kt
    fun sayHello(name: String) {
        println("hello $name")
    }
    //java test
    TestPackageMethodKt.sayHello("zhao");
    

    如果想改变生成的默认类名,可以在kt文件中package声明前添加注解。

    //改变默认生成的Java类名
    @file:JvmName("MyPackageMethodTest")
    

    object静态函数

    之前讲到object类为单例类,内部实现是通过饿汉式实现单例,在类中有一个本类的静态实例,因此当在java中访问此object类中方法的时需通过此静态实例,该实例的默认名字统一为INSTANCE

    //ObjectTest.kt
    object ObjectTest {
        fun objectMethod() {
        }
    }
    
    //java call
    ObjectTest.INSTANCE.objectMethod();
    

    伴生对象

    伴生对象同样是通过静态实现,只不过静态方法在一个Companion内部类中,因此Java调用需显示声明Companion类名。

    //TestStatic.kt
    open class TestStatic {
        companion object {
            fun create(): TestStatic {
                return TestStatic()
            }
        }
    }
    
    //java call
    TestStatic.Companion.create()
    

    异常检查

    与Java语言非常大的不同是Kotlin不做异常检查,这就导致在Java中声明的检查异常不需在Kotlin代码中捕获,从而发生意想不到的崩溃,反之亦然。

    //TestKotlinException.kt
    object TestKotlinException {
        //抛出异常但方法不需异常声明
        fun getException() {
            throw Exception("I am an exception in kotlin")
        }
    }
    
    //java call
    public static void testException() {
        //编译通过 但运行会发生异常
        TestKotlinException.INSTANCE.getException();
    }
    

    如果想改变此默认行为,我们需要在Kotlin方法前添加@Throws(Exception::class)注解。

    @Throws(Exception::class)
    fun getException() {
        throw Exception("I am an exception in kotlin")
    }
    

    此时java调用端会出现期望的编译错误。

    //unhandled exception: java.lang.Exception
    TestKotlinException.INSTANCE.getException();
    

    相关文章

      网友评论

        本文标题:Kotlin基本语法之(九)Kotlin与java互操作

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