必须启用 kotlin 插件,否则 compilekotlin 任务不会注册;gradle 默认只处理 java,需显式声明 kotlin("jvm") 或 kotlin("android") 插件,并正确配置 sourcesets 中的 kotlin.srcdirs 和 java.srcdirs,同步 jvm target 版本,且混合调用时须合理使用 @jvm* 注解。

必须启用 Kotlin 插件,否则 compileKotlin 任务根本不会注册
Gradle 默认只认 Java —— 即便你项目里全是 .kt 文件,只要没显式应用 Kotlin 插件,gradle build 就只会跑 compileJava,Kotlin 源码直接被忽略。Kotlin 编译不是“自动附带”的功能,它由 kotlin-gradle-plugin 提供独立任务(如 compileKotlin),该插件还负责把 Kotlin 和 Java 编译任务串成依赖链(比如 compileKotlin → compileJava)。
正确做法是:在 build.gradle.kts 顶部声明插件:
plugins {
kotlin("jvm") version "1.9.24" // 或 kotlin("android") for Android
java
}
注意:kotlin("jvm") 已隐式包含 java 插件逻辑,但显式写上 java 更清晰,也避免某些旧版 Gradle 的 sourceSet 推导异常。
sourceSets 配置不等于“把路径塞进去就行”
很多人以为只要在 sourceSets.main.java.srcDirs 里加个 "src/main/kotlin" 就能混编,这是错的。Kotlin 源码必须走 kotlin.srcDirs,否则 compileKotlin 任务找不到输入;Java 源码必须走 java.srcDirs,否则 compileJava 会漏掉类。两者路径可以重叠,但语义不能混淆。
推荐配置(标准结构):
sourceSets {
main {
java.srcDirs("src/main/java")
kotlin.srcDirs("src/main/kotlin")
}
}
- 不要写
java.srcDirs("src/main/java", "src/main/kotlin")—— 这会让compileJava去尝试编译.kt文件,报错error: invalid flag: *.kt - 也不建议把 Kotlin 文件硬塞进
src/main/java—— IDE 可能识别为 Java 文件,补全/跳转失效,且违反语言职责分离 - 如果真要共目录(极少数遗留场景),得靠
kotlin.sourceSets手动桥接,但代价是失去 IDE 对 Kotlin 语法的完整支持
JVM target 版本不一致会直接导致 IncompatibleClassChangeError
Java 和 Kotlin 编译出的 class 文件必须运行在同一 JVM 字节码级别下。常见错误现象是:编译通过,但运行时报 IncompatibleClassChangeError 或 java.lang.NoSuchMethodError,尤其在调用 Kotlin 的扩展函数、data class 的 copy()、或 @JvmStatic 方法时。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
必须同步以下三处版本:
-
java.toolchain.languageVersion(Gradle 17+ 推荐方式) kotlinOptions.jvmTarget- Android 项目还需确认
android.compileSdk和android.targetSdk兼容该 JVM 版本
示例(JDK 17 环境):
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
kotlin {
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
}
旧写法 kotlinOptions { jvmTarget = "17" } 在新 Kotlin 插件中已弃用,会静默失效。
混合调用时要注意 @Jvm* 注解的触发条件
Kotlin 代码被 Java 调用一般没问题,但 Java 调用 Kotlin 的某些特性需要显式注解,否则编译期就失败:
-
@JvmOverloads:Kotlin 函数含默认参数,Java 调用时需生成重载方法 -
@JvmStatic:放在 companion object 中的方法,才能被 Java 当作 static 方法调用 -
@JvmField:绕过 getter/setter,暴露为 public final 字段(避免 Java 侧多一层封装) - 无注解的顶层函数会被编译到
FileNameKt.class中,Java 必须用FileNameKt.functionName()调用
这些不是“可选优化”,而是 Java/Kotlin ABI 互操作的契约。漏掉一个,Java 侧就可能编译不过,或者运行时找不到符号。
最易被忽略的是 JVM target 对齐和 @JvmOverloads 的使用场景 —— 它们不出现在编译错误里,却让 Java 侧调用链断裂,排查成本远高于配置本身。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










