You need to enable JavaScript to run this app. Kotlin Gradle项目运行Jar时报Ref$ObjectRef类的NoClassDefFoundError
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Gradle项目运行Jar时报Ref$ObjectRef类的NoClassDefFoundError

Kotlin可执行Jar运行报NoClassDefFoundError排查与修复

错误现象

执行gradle clean build生成可执行Jar运行时,抛出如下堆栈:

at xyz.colmmurphy.ktop.KtopKt.main(ktop.kt:16)
    at xyz.colmmurphy.ktop.KtopKt.main(ktop.kt)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Ref$ObjectRef
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:606)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoader.java:168)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    ... 2 more

反复核对所有业务实现代码,始终找不到触发异常的对应逻辑。

根因定位

报错找不到的kotlin.jvm.internal.Ref$ObjectRef是Kotlin标准库内置的运行时辅助类,既不是项目自定义的类,也不是第三方依赖提供的类。出现类找不到的问题和业务代码逻辑完全无关,说白了就是打出来的Jar包没有把Kotlin运行时(含kotlin-stdlib、协程运行时等依赖)的字节码打包进最终产物,运行时类加载器扫描不到这些内置类,直接抛错。
这种情况下反复排查业务代码自然没有结果,问题出在Gradle打包配置环节。

常见配置漏洞

出现打漏运行时依赖的场景通常是以下几种:

  • 直接使用Gradle默认的Jar任务打包,该任务仅会把项目自身编译生成的类打进去,完全不会附带任何依赖
  • 引入了Shadow打包插件但没有正确配置依赖合并规则,导致Kotlin相关依赖被过滤漏掉
  • 旧版本Kotlin Gradle插件的兼容Bug,没有正确追踪标准库的类引用

修复操作步骤

  1. 修改build.gradle配置,引入Shadow插件生成带全量依赖的可执行Fat Jar:
    plugins {
        // Kotlin JVM编译插件
        id 'org.jetbrains.kotlin.jvm'
        // 用于打全量依赖Jar的Shadow插件
        id 'com.github.johnrengelman.shadow' version '8.1.1'
        application
    }
    
    application {
        // 指定项目主类
        mainClass.set('xyz.colmmurphy.ktop.KtopKt')
    }
    
  2. 配置ShadowJar任务的Manifest信息,确保Jar入口正确:
    tasks.named('shadowJar') {
        archiveBaseName.set('ktop')
        archiveVersion.set('1.0.0')
        manifest {
            attributes 'Main-Class': 'xyz.colmmurphy.ktop.KtopKt'
        }
        // 合并依赖中的服务文件,避免协程等库的配置被覆盖
        mergeServiceFiles()
    }
    
  3. 执行打包命令生成最终产物,不要使用默认build任务生成的薄Jar:
    gradle clean shadowJar
    
  4. 运行build/libs目录下带all后缀的Jar包,即可正常启动,不会再报找不到Kotlin内置类的错误。

附带的代码逻辑隐患

这类打包问题修复后运行代码还可能踩到其他坑,提前调整可以避免后续报错:

  • 代码中通过GlobalScope.launch给lateinit变量赋值的逻辑,目前靠Thread.sleep(6000)硬等协程执行完成的方式不可靠,如果协程执行延迟超过等待时间,读取未初始化的lateinit变量会直接抛UninitializedPropertyAccessException
  • CPUCore类的infoList属性实现冗余:构造时传入了从/proc/stat读取的行字符串,但每次取值都会重新全量读取/proc/stat文件,既拖慢性能,也和构造函数传入的参数逻辑割裂
  • readCPUUsage方法操作文件输入流时没有用use块自动关闭资源,长时间运行会导致文件句柄泄漏

内容的提问来源于stack exchange,提问作者colmmurphyxyz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.04 00:54:03