带值类的二级构造函数与主构造函数JVM签名冲突问题求助
带值类的二级构造函数与主构造函数JVM签名冲突问题求助
兄弟我太懂你这个烦恼了!用值类做类型安全本来是件省心的事,结果碰到JVM签名冲突的坑,常用的注解还都帮不上忙,确实头疼。
先给你捋清楚问题根源:你用的@JvmInline值类在JVM层面会被自动脱箱,所以接收PersonId的二级构造,最终生成的JVM参数还是Int,和主构造的(Int)签名完全一致,这就导致了平台声明冲突。而且你说的没错,@JvmSynthetic不能用在构造函数上,@JvmName也没法修改构造函数的签名,这俩注解确实派不上用场。
下面给你两个可行的解决方案,其中一个能满足你保留二级构造的需求:
变通方案:利用vararg规避签名冲突
这个方法有点取巧,但完美符合你想用二级构造的要求。思路是把二级构造的参数转成vararg数组形式,让JVM生成完全不同的签名(数组类型vs单个Int),从而避开冲突:
@JvmInline value class PersonId(val id: Int) data class PersonJson(val id: Int) { // 通过vararg数组展开调用主构造,规避JVM签名冲突 constructor(id: PersonId) : this(*intArrayOf(id.id)) }
在Kotlin里调用完全正常,PersonJson(PersonId(123))和PersonJson(123)都能正常工作,而且因为你不需要对Java可见,Java那边也不会用到这些构造函数,完全不影响你的使用场景。
备选方案:伴生对象工厂方法(规范写法)
如果觉得上面的vararg写法有点别扭,那伴生对象的工厂方法是最规范的解决方式,代码可读性也更高:
@JvmInline value class PersonId(val id: Int) data class PersonJson(val id: Int) { companion object { fun fromPersonId(id: PersonId) = PersonJson(id.id) } }
调用的时候用PersonJson.fromPersonId(PersonId(123)),虽然多了个方法名,但完全没有签名冲突的问题,代码逻辑也更清晰。
内容来源于stack exchange
相关产品推荐
相关产品推荐

