前言

Java 不能直接理解 Kotlin 语法(顶层函数、伴生对象、data class、suspend、private 等),Kotlin 会编译成特殊的 Java 结构,Java 必须按编译后的规则调用。

下面是精心整理的常用避坑速查清单:

一、顶层函数/顶层常量(*.kt 文件内直接定义)

Kotlin 代码(文件名:FileUtil.kt)

fun printLog(msg: String) {}
const val VERSION = "2.1.0"
val desc = "工具类"

Java 调用规则

  1. 函数/普通属性:文件名+Kt 作为类名调用
  2. const val 编译期常量可直接静态访问
FileUtilKt.printLog("test");
String v = FileUtilKt.VERSION;
String d = FileUtilKt.getDesc();

约束

不能直接 FileUtil.printLog(),必须带后缀 Kt;普通 val 在 Java 是 getXXX()

二、companion object 伴生对象

原始写法(无注解)

class User {
    companion object {
        fun create() {}
        const val MAX = 100
    }
}

Java 调用:

User.Companion.create();
int max = User.MAX;

规范优化:添加 @JvmStatic,消除 Companion

companion object {
    @JvmStatic fun create() {}
    const val MAX = 100
}

Java 简洁调用:

User.create();

约束

不加 @JvmStatic 必须写 .Companionconst val 不受影响。

三、带默认值的函数参数

无注解(Java 强制传全量参数)

fun show(name: String, age: Int = 18) {}

Java 只能完整传参:

show("Tom", 18);
// show("Tom"); 编译报错

规范优化:@JvmOverloads 生成多重载方法

@JvmOverloads
fun show(name: String, age: Int = 18) {}

Java 两种调用都支持:

show("Tom");
show("Tom", 20);

约束

Java 原生不识别 Kotlin 默认参数,不加注解无法省略参数。

四、单例 object 类

Kotlin

object HttpManager {
    fun request() {}
}

Java 调用

HttpManager.INSTANCE.request();

约束

没有静态方法,必须通过内置 INSTANCE 对象访问;
如需静态调用,函数上加 @JvmStatic

object HttpManager {
    @JvmStatic fun request() {}
}
// Java
HttpManager.request();

五、Kotlin 属性 val / var

Kotlin

class Book {
    val id: Long = 1L       // 只读
    var title: String = ""  // 可读可写
}

Java 调用(自动生成 getter / setter)

Book book = new Book();
long id = book.getId();
String t = book.getTitle();
book.setTitle("Kotlin实战");

约束

Java 不能直接 .id / .title,必须使用 getter/setter。

六、internal 修饰符(模块内可见)

Kotlin

internal fun innerFunc() {}
internal val code = 200

约束

Java 完全无法访问,编译直接报错;跨模块/Java 代码不要用 internal

七、空安全类型(关键坑点)

Kotlin 不可空(String,禁止null)

fun setName(name: String) {}

Java 可强行传入 null,运行抛出空指针:

setName(null); // 运行崩溃

Kotlin 可空(String?)

fun setNick(nick: String?) {}

Java 传 null 安全:

setNick(null);

规范

对外提供给 Java 调用的接口,不确定入参是否为空时,统一声明可空 ?

八、suspend 挂起函数(Java 无法直接调用)

Kotlin

suspend fun fetchData(): String { return "" }

约束

Java 不存在协程上下文,直接调用编译报错。

规范方案

封装普通函数,使用协程调度器包装,提供 Java 可用回调接口:

fun fetchDataJava(callback: (String) -> Unit) {
    CoroutineScope(Dispatchers.IO).launch {
        val res = fetchData()
        callback(res)
    }
}

Java 调用:

fetchDataJava(result -> {
    System.out.println(result);
    return Unit.INSTANCE;
});

九、高阶函数 / Lambda 参数

Kotlin

fun listenEvent(block: (Int) -> Unit) {}

Java 调用规范

使用 Function1,返回值必须携带 Unit.INSTANCE

listenEvent(num -> {
    System.out.println(num);
    return Unit.INSTANCE;
});

十、data class 数据类

Kotlin

data class Student(val name: String, val age: Int)

Java 使用

  1. 构造正常 new
  2. 获取属性推荐 getter,不推荐 component 组件函数
Student s = new Student("Jack", 16);
String name = s.getName(); // 推荐
int age = s.getAge();
// s.component1() 不推荐,可读性差

十一、常用注解速记(Java 适配专用)

注解 作用场景 效果
@JvmStatic companion object / object 生成静态方法,Java 无需写 Companion/INSTANCE
@JvmOverloads 带默认参数函数 Java 生成多个重载,支持省略参数
@JvmField val/var 属性 Java 可直接访问字段,不用 getter
@JvmName 顶层文件 修改 Java 生成的类名,去掉 Kt 后缀

十二、核心约束总览(一句话总结)

  1. 顶层函数带 Kt 后缀;
  2. 伴生/单例不加 @JvmStatic 必须写 Companion / INSTANCE;
  3. Java 不支持默认参数、suspend、internal;
  4. Kotlin 属性在 Java 只能通过 getter/setter;
  5. Java 可传 null 破坏 Kotlin 非空校验,线上易空指针;
  6. Lambda 需要返回 Unit.INSTANCE

更多推荐