【Kotlin 初学者】Java和Kotlin互操作

简介: 一、Kotlin调用Java1.1 互操作性与可空性1.2 类型映射1.3 属性访问二、Java调用Kotlin2.1 @JvmName2.2 @JvmField2.3 @JvmStatic2.4 @JvmOverloads2.4.1 未使用@JvmOverloads注解2.4.2 使用@JvmOverloads注解2.5 @Throws2.6 函数类型操作

作者简介:CSDN博客专家、华为云·云享专家认证

系列专栏:Kotlin 初学者


一、Kotlin调用Java


1.1 互操作性与可空性


1.2 类型映射


1.3 属性访问


二、Java调用Kotlin


2.1 @JvmName


2.2 @JvmField


2.3 @JvmStatic


2.4 @JvmOverloads


2.4.1 未使用@JvmOverloads注解


2.4.2 使用@JvmOverloads注解


2.5 @Throws


2.6 函数类型操作




一、Kotlin调用Java


1.1 互操作性与可空性


       Java世界里所有对象都是null,当一个Kotlin函数返回String类型值,它是可空的。

建立一个 Java 类


class JavaUser {
    public String userInfo(){
        return "Java-帅次";
    }
    //返回null
    public String family(){
        return null;
    }
}


Kotlin 调用 Java 方法


fun main() {
    var user = JavaUser()
    println(user.userInfo())//
    //使用时报错:NullPointerException
//    println(user.family().length)
    //平台类型,可能为null
    var fam = user.family()
    //当fam为null时,fam?.length返回null
    println(fam?.length)//null
}


微信图片_20220525112838.png


1.2 类型映射


       代码运行时,所有的映射类型都会重新映射回对应的Java类型。

Java定义属性类型


class JavaUser {
    public String name = "Java";
    ...
}


Kotlin 查看类型


fun main() {
    println(user.name.javaClass)//查看类型:class java.lang.String
}


1.3 属性访问


       刚才使用public修饰属性,在Kotlin可以直接调用,那么我们用private呢?

Java定义属性


class JavaUser {
    private int age =18;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    ...
}


Kotlin 使用


fun main() {
    println(user.age)
    user.age = 12
    println(user.age)
    println(user.age.javaClass)
}


如果仅使用private而不设置get/set方法 Kotlin是无法调用的,当设置了get/set方法。Kotlin可以直接调用其属性,而不用调用get/set方法(默认调用get/set方法),如下图:


微信图片_20220525113220.png


二、Java调用Kotlin


2.1 @JvmName


       可以使用JvmName注解指定编译类的名字。


2.1.1 在KotlinUser文件中定义kotlinUserInfo()函数


package com.scc.kotlin.primary.jandk
fun kotlinUserInfo() = "来自Kotlin的招呼"


2.1.2 在JavaMain使用main方法调用Kotlin的kotlinUserInfo()函数


package com.scc.kotlin.primary.jandk;
class JavaMain {
    public static void main(String[] args) {
        System.out.println(KotlinUserKt.kotlinUserInfo());//来自Kotlin的招呼
    }
}


觉得KotlinUserKt不好看,咱们给它换个名字,或者说起个别名。


2.1.3 在Kotlin文件最上方添加@JvmName


       这个必须写在文件最顶部。


@file:JvmName("SCKotlin")
package com.scc.kotlin.primary.jandk
fun kotlinUserInfo() = "来自Kotlin的招呼"


2.1.4 调用@JvmName设置的名字


    public static void main(String[] args) {
//        System.out.println(KotlinUserKt.kotlinUserInfo());//来自Kotlin的招呼
        System.out.println(SCKotlin.kotlinUserInfo());//来自Kotlin的招呼
    }


2.2 @JvmField


       在Java里,不能直接访问Kotlin定义的字段(如下:name),所以必须调用getName,然而,你可以给Kotlin属性添加@JvmField注解,暴露它的支持字段给Java调用者,从而避免使用getter方法。


class KotlinSc{
    @JvmField
    var name = "Kotlin-SC"
    var age = 13
}


KotlinSc的name属性添加了@JvmField注解,Java可以直接调用,age属性未添加@JvmField注解,所以Java无法直接调用,当然你可以通过get/set方法调用age属性。如下图:


微信图片_20220525113901.png

class JavaMain {
    public static void main(String[] args) {
        KotlinSc kotlinSc=new KotlinSc();
        System.out.println(kotlinSc.name);//Kotlin-SC
    }
}


2.3 @JvmStatic


       对函数使用该注解,kotlin编译器将生成另一个静态方法;


       对属性使用该注解,kotlin编译器将生成其他的setter和getter方;


       这个注解的作用其实就是消除Java调用Kotlin的companion object对象时不能直接调用其静态方法和属性的问题.


注意:此注解只能在companion object使用


class KotlinSc {
    ...
    //伴生对象
    companion object{
        var height = 178
        fun evaluate() = "SC是一个学习Kotlin的小渣渣"
    }
}


在kotlin中可直接使用,但是在Java中则必须


//在kotlin中可直接使用
fun main() {
    println(KotlinSc.height.toString().plus("CM"))//178CM
    println(KotlinSc.evaluate())//SC是一个学习Kotlin的小渣渣
}
//在Java中则相对复杂一些。
    public static void main(String[] args) {
        KotlinSc kotlinSc=new KotlinSc();
        System.out.println(kotlinSc.Companion.getHeight()+"CM");//178CM
        System.out.println(kotlinSc.Companion.evaluate());//SC是一个学习Kotlin的小渣渣
    }


给伴生对象的函数使用@JvmStatic注解,属性还是使用


class KotlinSc {
    ...
    companion object{
        @JvmField
        var height = 178
        @JvmStatic
        fun evaluate() = "SC是一个学习Kotlin的小渣渣"
    }
}


Java调用添加注解的函数和属性


    public static void main(String[] args) {
        KotlinSc kotlinSc=new KotlinSc();
        System.out.println(KotlinSc.height+"CM");//178CM
        System.out.println(KotlinSc.evaluate());//SC是一个学习Kotlin的小渣渣
    }


2.4 @JvmOverloads


       JvmOverloads注解协助产生Kotlin函数的重载版本。设计一个可能会暴露给Java用户使用的API时,记得使用@JvmOverloads注解,这样,无论你是Kotlin开发者还是Java开发者,都会对这个API的可靠性感到满意。


2.4.1 未使用@JvmOverloads注解


     定义一个未使用@JvmOverloads注解的Kotlin函数


fun kotlinEat(bread: String = "巧克力面包", meat: String = "鸡翅") {
    println("$bread-搭配-$meat-美极了")
}


使用kotlin调用,一点问题没有,妥妥的。


fun main() {
    kotlinEat();//巧克力面包-搭配-鸡翅-美极了
    kotlinEat("橙香面包")//橙香面包-搭配-鸡翅-美极了
    kotlinEat(meat = "羊肉")//巧克力面包-搭配-羊肉-美极了
    kotlinEat("奶油长杆面包","牛肉")//奶油长杆面包-搭配-牛肉-美极了
}


使用Java调用,仅能调用传入两个参数的方法,而不能像Kotlin那样随意调用。


微信图片_20220525114603.png


2.4.2 使用@JvmOverloads注解


       我们在给kotlinEat(bread: String = "巧克力面包", meat: String = "鸡翅")函数添加@JvmOverloads注解。


@JvmOverloads
fun kotlinEat(bread: String = "巧克力面包", meat: String = "鸡翅") {
    println("$bread-搭配-$meat-美极了")
}


微信图片_20220525114640.png


    public static void main(String[] args) {
        SCKotlin.kotlinEat("Java牌面包");//Java牌面包-搭配-鸡翅-美极了
    }


为什么会这样?咱们看看:


       未使用@JvmOverloads注解


微信图片_20220525114711.png


使用@JvmOverloads注解,此处截图不全,两个参数的方法没截取到,感兴趣的自己去玩玩。


微信图片_20220525114744.png


使用@JvmOverloads注解后强迫该函数重载,这样Java就可以进行不同场景调用了。


2.5 @Throws


       使用@Throws注解,声明这个方法要检查Exception。


//这里的Throws是必须添加的,要不Java那边无法捕捉这个异常
@Throws(IOException::class)
fun kotlinEatException(){
    println("吃东西呛住了")
    throw IOException()
}


  编译成Java代码,如下:


微信图片_20220525114824.png


    public static void main(String[] args) {
        try {
            SCKotlin.kotlinEatException();//吃东西呛住了
        } catch (IOException e) {
            System.out.println(e);//java.io.IOException
            e.printStackTrace();
        }
    }


微信图片_20220525114844.png


2.6 函数类型操作


       函数类型和匿名函数能提供高效的语法用于组件间的交互,是Kotlin编程语言里比较新颖的特性。


       他们简洁的语法因->操作符而实现,但Java8之前的JDK版本并并不支持lambda表达式。


       在Java里,Kotlin函数类型使用FunctionN这样的名字的接口来表示的,FunctionN中的N代表值参数目。这样的Function接口从Function0到Function22(23个),每一个FunctionN都包含一个invoke函数,专用于调用函数类型函数,所以,任何时候需要调一个函数类型,都用它调用invoke。


val hair = {colorHair:String ->
    println( "头发染成 $colorHair 即可")
}
val hairTwo = {colorHair:String,lengthHair:Int ->
    println( "头发染成$colorHair,剪至$lengthHair-厘米即可")
}


        Function1<String, Unit> hair = SCKotlin.getHair();
        hair.invoke("红色");//头发染成 红色 即可
        Function2<String, Integer, Unit> hairTwo = SCKotlin.getHairTwo();
        hairTwo.invoke("蓝色",8);//头发染成蓝色,剪至8-厘米即可

微信图片_20220525114955.png


Function接口从Function0到Function22(23个)


微信图片_20220525115016.png

相关文章
|
17天前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
39 1
|
3月前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
32 3
Android面试题之Java 泛型和Kotlin泛型
|
3月前
|
安全 Java 编译器
Kotlin和Java 单例模式
Kotlin和Java 单例模式
41 1
|
3月前
|
安全 Java Android开发
Kotlin与Java:Android开发的双剑合璧
【6月更文挑战第9天】Kotlin和Java在Android开发中形成互补态势。Java凭借广泛社区支持和丰富的类库资源占据主导,但其语法繁琐和空指针问题限制了发展。Kotlin,设计来解决这些问题,以其简洁、安全、高效的特性逐渐兴起。Kotlin的互操作性允许与Java无缝集成,提升开发效率,减少错误。两者结合提高了代码质量和开发者的灵活性,促进了Android开发社区的繁荣。开发者应把握这种&quot;双剑合璧&quot;,适应技术发展。
50 10
|
3月前
|
Java Android开发 Kotlin
Android面试题:App性能优化之Java和Kotlin常见的数据结构
Java数据结构摘要:ArrayList基于数组,适合查找和修改;LinkedList适合插入删除;HashMap1.8后用数组+链表/红黑树,初始化时预估容量可避免扩容。SparseArray优化查找,ArrayMap减少冲突。 Kotlin优化摘要:Kotlin的List用`listOf/mutableListOf`,Map用`mapOf/mutableMapOf`,支持操作符重载和扩展函数。序列提供懒加载,解构用于遍历Map,扩展函数默认参数增强灵活性。
38 0
|
4月前
|
Java Kotlin
java调用kotlin代码编译报错“找不到符号”的问题
java调用kotlin代码编译报错“找不到符号”的问题
211 10
|
3月前
|
自然语言处理 Java Android开发
Java一分钟之Kotlin与Java互操作
【6月更文挑战第12天】本文探讨了Kotlin与Java之间的互操作性,重点关注了两者在调用对方代码时的常见问题和解决策略。在Kotlin调用Java时,需注意Java的`package-private`访问限制、泛型擦除和重载解析差异。建议使用`public`修饰符、明确泛型类型并了解重载规则。在Java调用Kotlin时,需处理Kotlin特性的不可见性、命名冲突和顶层函数调用。可以通过遵循Java习惯、使用`@JvmName`注解和封装顶层函数为类方法来避免问题。通过掌握这些技巧,开发者能更好地在多语言环境下工作。
37 0
|
4月前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能对比
【5月更文挑战第4天】在移动开发的世界中,性能一直是衡量应用质量的重要指标。随着Kotlin的兴起,许多Android开发者开始考虑是否应该从传统的Java迁移到Kotlin。本文通过深入分析两者在Android平台上的性能差异,帮助开发者理解Kotlin在实际项目中的表现,并提供选择编程语言时的参考依据。
66 5
|
4月前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【5月更文挑战第29天】 在移动开发领域,性能优化一直是开发者追求的关键目标。随着Kotlin在Android开发中的普及,了解其与传统Java语言在性能方面的差异成为一项重要议题。本文通过深入分析和对比两种语言的运行效率、启动时间以及内存消耗,为开发者在选择编程语言时提供数据支持和实践指南,从而帮助他们构建更加高效的Android应用。
|
4月前
|
安全 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【5月更文挑战第16天】 在移动开发领域,性能一直是开发者关注的焦点。随着Kotlin语言的普及,其与Java在Android应用中的性能表现成为热门话题。本文将深入分析Kotlin和Java在Android平台上的性能差异,并通过实际测试数据来揭示二者在编译速度、应用启动时间以及运行效率方面的表现。我们的目标是为开发者提供一个参考依据,以便在选择合适的编程语言时做出更加明智的决策。