Kotlin创建类次级构造函数时报JVM签名冲突该如何解决
签名冲突原因
JVM存在泛型擦除机制,代码中定义的List<SlideModel>、List<HomeTrendingAdsModel>、List<HomeCategoryModel>这类带泛型的类型,在编译为字节码时会擦除泛型信息,统一变为List类型。
你的三个次级构造函数入参结构都是(Int?, List<*>),擦除后完全一致,因此JVM会判定为重复声明,抛出冲突错误。
而你参考的SlideModel类没有出现冲突,是因为它的构造函数第一个入参分别为String?和Int?,属于完全不同的JVM基础类型,不存在擦除导致的签名重合问题。
解决方案
这里提供3种常用的解决方式,优先推荐第一种,更符合多类型RecyclerView的设计规范:
方案1:改用密封类定义多类型模型(推荐)
密封类天然适合多类型场景,不需要冗余的空字段和viewType判断,类型安全:
sealed class TestingModel { // 每个子类型对应一种viewType,不需要额外声明viewType常量 data class ImageSlider(val sliderList: List<SlideModel>) : TestingModel() data class TrendingAds(val adsList: List<HomeTrendingAdsModel>) : TestingModel() data class Category(val categoryList: List<HomeCategoryModel>) : TestingModel() }
在RecyclerView.Adapter中获取viewType时,直接判断实例类型即可:
override fun getItemViewType(position: Int): Int { return when(dataList[position]) { is TestingModel.ImageSlider -> 0 is TestingModel.TrendingAds -> 1 is TestingModel.Category -> 2 } }
方案2:使用伴生对象工厂方法替代多构造函数
如果你不想修改原有类结构,可以通过工厂方法避免构造函数签名冲突:
class TestingModel private constructor( var viewType: Int? = 0, var imageSliderList: List<SlideModel>? = null, var adsList: List<HomeTrendingAdsModel>? = null, var categoryList: List<HomeCategoryModel>? = null ) { companion object { const val IMAGE_SLIDER: Int = 0 const val TRENDING_ADS: Int = 1 const val CATEGORY: Int = 2 fun createImageSlider(sliderList: List<SlideModel>) = TestingModel( viewType = IMAGE_SLIDER, imageSliderList = sliderList ) fun createTrendingAds(adsList: List<HomeTrendingAdsModel>) = TestingModel( viewType = TRENDING_ADS, adsList = adsList ) fun createCategory(categoryList: List<HomeCategoryModel>) = TestingModel( viewType = CATEGORY, categoryList = categoryList ) } }
使用时直接调用对应工厂方法即可:TestingModel.createImageSlider(你的列表)
方案3:使用@JvmName注解修改构造函数签名
如果一定要保留多构造函数的写法,可以给构造函数添加@JvmName注解修改编译后的JVM签名,实际开发中不推荐这种写法,可读性较差。
内容的提问来源于stack exchange,提问作者Harshit Choudhary
相关产品推荐
相关产品推荐

