【Kotlin】互操作之Java调用Kotlin避坑指南
前言
Java 不能直接理解 Kotlin 语法(顶层函数、伴生对象、data class、suspend、private 等),Kotlin 会编译成特殊的 Java 结构,Java 必须按编译后的规则调用。
下面是精心整理的常用避坑速查清单:
一、顶层函数/顶层常量(*.kt 文件内直接定义)
Kotlin 代码(文件名:FileUtil.kt)
funprintLog(msg:String){}constvalVERSION="2.1.0"valdesc="工具类"Java 调用规则
- 函数/普通属性:文件名+
Kt作为类名调用 const val编译期常量可直接静态访问
FileUtilKt.printLog("test");Stringv=FileUtilKt.VERSION;Stringd=FileUtilKt.getDesc();约束
不能直接FileUtil.printLog(),必须带后缀Kt;普通val在 Java 是getXXX()。
二、companion object 伴生对象
原始写法(无注解)
classUser{companionobject{funcreate(){}constvalMAX=100}}Java 调用:
User.Companion.create();intmax=User.MAX;规范优化:添加@JvmStatic,消除 Companion
companionobject{@JvmStaticfuncreate(){}constvalMAX=100}Java 简洁调用:
User.create();约束
不加@JvmStatic必须写.Companion;const val不受影响。
三、带默认值的函数参数
无注解(Java 强制传全量参数)
funshow(name:String,age:Int=18){}Java 只能完整传参:
show("Tom",18);// show("Tom"); 编译报错规范优化:@JvmOverloads生成多重载方法
@JvmOverloadsfunshow(name:String,age:Int=18){}Java 两种调用都支持:
show("Tom");show("Tom",20);约束
Java 原生不识别 Kotlin 默认参数,不加注解无法省略参数。
四、单例 object 类
Kotlin
objectHttpManager{funrequest(){}}Java 调用
HttpManager.INSTANCE.request();约束
没有静态方法,必须通过内置INSTANCE对象访问;
如需静态调用,函数上加@JvmStatic:
objectHttpManager{@JvmStaticfunrequest(){}}// JavaHttpManager.request();五、Kotlin 属性 val / var
Kotlin
classBook{valid:Long=1L// 只读vartitle:String=""// 可读可写}Java 调用(自动生成 getter / setter)
Bookbook=newBook();longid=book.getId();Stringt=book.getTitle();book.setTitle("Kotlin实战");约束
Java 不能直接.id/.title,必须使用 getter/setter。
六、internal 修饰符(模块内可见)
Kotlin
internalfuninnerFunc(){}internalvalcode=200约束
Java 完全无法访问,编译直接报错;跨模块/Java 代码不要用internal。
七、空安全类型(关键坑点)
Kotlin 不可空(String,禁止null)
funsetName(name:String){}Java 可强行传入null,运行抛出空指针:
setName(null);// 运行崩溃Kotlin 可空(String?)
funsetNick(nick:String?){}Java 传 null 安全:
setNick(null);规范
对外提供给 Java 调用的接口,不确定入参是否为空时,统一声明可空?。
八、suspend 挂起函数(Java 无法直接调用)
Kotlin
suspendfunfetchData():String{return""}约束
Java 不存在协程上下文,直接调用编译报错。
规范方案
封装普通函数,使用协程调度器包装,提供 Java 可用回调接口:
funfetchDataJava(callback:(String)->Unit){CoroutineScope(Dispatchers.IO).launch{valres=fetchData()callback(res)}}Java 调用:
fetchDataJava(result->{System.out.println(result);returnUnit.INSTANCE;});九、高阶函数 / Lambda 参数
Kotlin
funlistenEvent(block:(Int)->Unit){}Java 调用规范
使用Function1,返回值必须携带Unit.INSTANCE
listenEvent(num->{System.out.println(num);returnUnit.INSTANCE;});十、data class 数据类
Kotlin
dataclassStudent(valname:String,valage:Int)Java 使用
- 构造正常 new
- 获取属性推荐 getter,不推荐 component 组件函数
Students=newStudent("Jack",16);Stringname=s.getName();// 推荐intage=s.getAge();// s.component1() 不推荐,可读性差十一、常用注解速记(Java 适配专用)
| 注解 | 作用场景 | 效果 |
|---|---|---|
| @JvmStatic | companion object / object | 生成静态方法,Java 无需写 Companion/INSTANCE |
| @JvmOverloads | 带默认参数函数 | Java 生成多个重载,支持省略参数 |
| @JvmField | val/var 属性 | Java 可直接访问字段,不用 getter |
| @JvmName | 顶层文件 | 修改 Java 生成的类名,去掉 Kt 后缀 |
十二、核心约束总览(一句话总结)
- 顶层函数带
Kt后缀; - 伴生/单例不加
@JvmStatic必须写 Companion / INSTANCE; - Java 不支持默认参数、suspend、internal;
- Kotlin 属性在 Java 只能通过 getter/setter;
- Java 可传 null 破坏 Kotlin 非空校验,线上易空指针;
- Lambda 需要返回
Unit.INSTANCE。
