You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中调用Kotlin定义的Value class及相关实例创建方法

问题原因

Kotlin的@JvmInline value class(原内联类)为了实现无额外性能损耗的类型包装,在JVM字节码层面会做特殊处理:

  • 所有接收或返回value class类型的Kotlin函数,默认会触发名称混淆(name mangling),函数名会被自动加上特殊后缀,Java侧无法识别到原始名称的函数,所以会出现buildCountry()方法不存在的现象。你可以正常调用buildString()是因为它返回普通String类型,不会触发混淆逻辑。
  • 该混淆机制和是否添加@JvmStatic无关,只要返回值是value class就会触发,所以加@JvmStatic没有效果。
  • 同时value class的构造函数默认私有,是Kotlin为了保证内联类实例只能按规则生成,避免Java直接构造破坏内联逻辑。

解决方法

方案1:添加@JvmName显式指定Java侧可见的函数名(最推荐)

该方案可以保留value class的内联性能优势,同时兼容Java调用,只需要给返回value class的函数添加注解即可:

class IdentifierFactory {
    companion object {
        fun buildString(): String {
            return "hello"
        }

        // 显式指定Java侧可见的方法名
        @JvmName("buildCountry")
        fun buildCountry(): CountryId {
            return CountryId.empty()
        }
        
        // 配合@JvmStatic使用也可以
        @JvmStatic
        @JvmName("buildCountryStatic")
        fun buildCountryStatic(): CountryId = CountryId.empty()
    }
}

修改后Java侧即可正常调用:

// 调用Companion方法
CountryId countryId = IdentifierFactory.Companion.buildCountry();
// 调用静态方法
CountryId countryId2 = IdentifierFactory.buildCountryStatic();

方案2:改为普通data class(无性能要求时可用)

如果你的场景对性能没有极致要求,只是需要类型安全的包装,可以直接把value class改成普通data class,完全不需要额外适配即可兼容Java调用:

data class CountryId(private val id: UUID) {
    override fun toString(): String = id.toString()
    companion object { fun empty(): CountryId = CountryId(EMPTY_UUID) }
}

方案3:基础类型中转(仅特殊场景使用)

如果Java侧只需要拿到CountryId对应的原始值,也可以在工厂类新增返回UUID类型的方法,Java侧拿到底层值后需要转CountryId时再到Kotlin侧处理,该方案适配成本较高,无特殊需求不推荐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 17:54:03