Kotlin第十七讲---注解篇

内容简介

Kotlin 基础篇差不多快要完结了,接下来我们来讲讲 Kotlin 与 Java 之间的爱恨情仇(相互调用)。  

众所周知 Kotlin 是完全兼容 Java 的,它们之间的代码是相互可以调用的,但是由于语法上的不同 Java 调用 Kotlin 代码多少有点小别扭。  

 Kotlin 为我们提供了一些注解,来解决这些别扭。

file:JvmName

还记得包级函数吗?我们 Java 要调用包级函数要如何调用呢(想想包级函数的原理)?

Kot.kt 文件中定义:

package com.qihoo.kot
fun call(){
    println("我是包级函数")
}

Java 调用

public class TestJava {
    public static void main(String[] args) {
        /**
         * Java 中调用需要指定类
         * 调用方式:Kotlin的文件名+Kt.调用方法()
         *
         * 好头疼还需要加个 Kt
         */
        KotKt.call();
    }
}

上面代码注意到 Java 调用还需要加一个 Kt 的后缀,如何解决呢?

其实解决这个问题很简单,只需要通过 @file:JvmName("类名") 告诉编译器生成的类名我自己指定。

// 注意这个要注解在包上
@file:JvmName("Kot")
package com.qihoo.kot
/**
 * Kotlin 中定义包级函数 call
 */
fun call(){
    println("我是包级函数")
}
public class TestJava {
    public static void main(String[] args) {
        /**
         * Java 这里就可以直接使用 Kot 啦
         */
        Kot.call();
    }
}

温馨提示:配置混淆的时候要注意哦,生成的类名最好别乱改。

JvmField

Kotlin 定义的变量,如果是 val 类型会生成 getXX 方法, var 类型变量会生成 getXX 和 setXX 方法。

Java 想获取这些变量,只能通过 getXX 方法去获取。

Kotlin 定义:

class Code(
    val name: String,
    val age: Int
) {
    var sex: String = "男"
}

Java 调用:

public class TestJava {
    public static void main(String[] args) {
        Code code = new Code("啊文", 18);
        /**
         * 由于我们是 val 变量,所以只有 get 方法
         *
         * Java 中可以直接通过 get 获取
         */
        code.getAge();
        code.getName();
        code.getSex();
    }
}

若 Java 中如果不想通过 getXX 或 setXX 来操控变量,可以在 Kotlin 中使用 @JvmField 注解变量即可。

class Code(
    @JvmField
    val name: String,
    @JvmField
    val age: Int
) {
    @JvmField
    var sex: String = "男"
}

JvmStatic

Kotlin 的静态方法是定义在伴生对象中, Java 想调用还需要通过获取伴生对象来进行调用。

class Code {
    /**
     * 定义伴生对象
     */
    companion object {
        fun writeCode(){
            println("writeCode")
        }
    }
}

在 Java 中调用,需要通过伴生对象。

public class TestJava {
    public static void main(String[] args) {
        /**
         * 调用伴生对象的方法
         */
        Code.Companion.writeCode();
    }
}

Kotlin 中通过 @JvmStatic 注解方法,即可解决此问题。

class Code {
    /**
     * 定义伴生对象
     */
    companion object {
        /**
         * 通过 JvmStatic 注解即可
         */
        @JvmStatic
        fun writeCode(){
            println("writeCode")
        }
    }
}

通过 @JvmStatic 注解方法,在 Java 中调用,不再需要通过伴生对象。

public class TestJava {
    public static void main(String[] args) {
        /**
         * 调用伴生对象的方法
         */
        Code.writeCode();
    }
}

补充:在 Kotlin 中定义的 object 类(单例类)的方法也可以通过 @JvmStatic 注解,可以让 Java 中调用时,不需要引用 INSTANCE 对象。

/**
 * 定义 Kotlin 的 object 类
 */
object Simple {
    /**
     * 通过 JvmStatic 修饰
     */
    @JvmStatic
    fun call(){
        print("call")
    }
}
// Java 尝试调用
public class TestJava {
    public static void main(String[] args) {
        // 以前的调用方式,还需要通过 INSTANCE 引用
        // Simple.INSTANCE.call();
        /**
         * 直接调用 call 方法
         */
        Simple.call();
    }
}

JvmOverloads

在 Kotlin 的世界中,存在一种超级好用的参数默认值的功能,我们一般使用这种方式来减少重载方法。但是 Java 没有这项功能呀?那 Java 调用带有默认参数的 Kotlin 方法会怎样呢?

Kotlin 中定义默认参数方法:

class Code {
    /**
     * 使用了默认参数
     */
    fun eat(food: String = "米饭") {
        println("吃$food")
    }
}

Java 中尝试去调用:

public class TestJava {
    public static void main(String[] args) {
        Code code = new Code();
        /**
         * 可以发现,没有默认参数的功能,必须要填写参数
         */
        code.eat("大鸡腿");
    }
}

从上面的代码可以注意到 Java 调用 Kotlin 默认参数方法是必须要传参的。其实这里大伙就要思考下 Kotlin 的默认参数难道不是通过函数重载的形式来实现的吗?其实还真不是,具体大家可以反编译下。

那如何解决呢?我们想让默认参数的方法,在 Java 中也能调用,调用的形式就是函数重载。其实我们只需要通过 @JvmOverloads 注解默认参数的 Kotlin 方法即可,这样在编译期就会生成重载方法。

Kotlin 中尝试使用 @JvmOverloads 修饰默认参数方法:

class Code {
    /**
     * 使用了默认参数,并使用 @JvmOverloads 注解
     */
    @JvmOverloads
    fun eat(food: String = "米饭") {
        println("吃$food")
    }
}

Java 中尝试去调用重载的方法:

public class TestJava {
    public static void main(String[] args) {
        Code code = new Code();
        /**
         * 可以调用无参的
         */
        code.eat();
        /**
         * 可以传参
         */
        code.eat("大鸡腿");
    }
}

补充:我曾经遇到一个坑,在 Andorid 中自定义 View 的时候, Android 中一定要重载 View 的 3 个构造方法,并且相互向下调用。在 Kotlin 中我通过默认参数就可以方便很多。但是我将自定义的 View 加入 xml 布局中,直接崩溃了。报错原因是没有重载 2 个参数的 View 构造方法,为何会这样呢?其实就是因为 Kotlin 的默认参数方法,并不是通过重载去实现的,我们只需要通过 @JvmOverloads 修饰构造方法即可。

class HorizontalLoadingView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    View(context, attrs, defStyleAttr) {
}

Synchronized

Kotlin 如何定义一个同步方法呢? Java 中可以通过 synchronized 修饰方法。 Kotlin 只需要通过 @Synchronized 注解方法即可。

Kotlin 同步代码块和 Java 的定义形式一样

Volatile

volatile 可见性,在 Java 定义单例的时候用过,它可以保证线程安全 3 大条件之一的可见性。 Kotlin 中只需要通过 @Volatile 注解即可。

file:JvmMultifileClass

可以将 2 个包下包级别函数放在指定类下,必须要配合 @file:JvmName("Utils") 让其生成的包级类一致。这个用处太少了,我感觉没啥用,反而让代码更加的混乱。

总结

通过以上的几个注解,我相信大家对 Java 与 Kotlin 互相调用有一定把握了吧。当然这只是我遇到的问题,不保证全部,不过这些注解足够应付我们实际开发啦。

推荐阅读

e9e428ca5f1ebd9f311e9d469abb5550.jpegf8ebb1cd0f023818a1b580591cacc160.jpeg

--END--

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值