jvm 无法在Kotlin中创建辅助构造函数

1l5u6lss  于 2022-11-07  发布在  Kotlin
关注(0)|答案(1)|浏览(201)

我想创建一个类

class TestingModel {

    companion object {
        const val IMAGE_SLIDER: Int = 0
        const val TRENDING_ADS: Int = 1
    }

    var viewType: Int? = 0
    var imageSliderList: List<SlideModel>? = null
    var adsList: List<HomeTrendingAdsModel>? = null
    var categoryList: List<HomeCategoryModel>? = null

    constructor(viewType: Int?, imageSliderList: List<SlideModel>? = null) {
        this.viewType = viewType
        this.imageSliderList = imageSliderList
    }

    constructor(viewType: Int?, adsList: List<HomeTrendingAdsModel>?) {
        this.viewType = viewType
        this.adsList = adsList
    }

    constructor(viewType: Int?, categoryList: List<HomeCategoryModel>?) {
        this.viewType = viewType
        this.categoryList = categoryList
    }
}

但是,我收到一个错误消息,说

Platform declaration clash: The following declarations have the same JVM signature ( (Ljava/lang/Integer;Ljava/util/List;)V): 
public constructor TestingModel(viewType: Int?, imageSliderList: List<SlideModel>? = ...) defined in com.example.theads.Model.TestingModel
public constructor TestingModel(viewType: Int?, categoryList: List<HomeCategoryModel>?) defined in com.example.theads.Model.TestingModel
public constructor TestingModel(viewType: Int?, adsList: List<HomeTrendingAdsModel>?) defined in com.example.theads.Model.TestingModel

我在图书馆看到做完全相同的没有错误。
编辑:另一个库在下面:

class SlideModel {

    var imageUrl: String? = null
    var imagePath: Int? = 0
    var title: String? = null
    var scaleType: ScaleTypes? = null

    constructor(imageUrl: String?, title: String? = null, scaleType: ScaleTypes?  = null) {
        this.imageUrl = imageUrl
        this.title = title
        this.scaleType = scaleType
    }

    constructor(imagePath: Int?, title: String?  = null, scaleType: ScaleTypes?  = null) {
        this.imagePath = imagePath
        this.title = title
        this.scaleType = scaleType
    }

    constructor(imageUrl: String?, scaleType: ScaleTypes?) {
        this.imageUrl = imageUrl
        this.scaleType = scaleType
    }

    constructor(imagePath: Int?, scaleType: ScaleTypes?) {
        this.imagePath = imagePath
        this.scaleType = scaleType
    }
}

我正在创建一个包含多个回收视图的回收视图。所以这个类成为回收视图的模型类,我希望它调用viewType,并与其他模型类的列表不同。谢谢

whitzsjs

whitzsjs1#

您提供的示例class SlideModel有多个构造函数。每个构造函数都有参数types的唯一组合。这一点很重要-因为Kotlin被转换为Java,而在Java中,参数的 names 会被忽略。JVM编译器不关心名称-它只关心参数types的顺序。

冲突的构造函数

让我们看一个更简单的例子(我将在本答案的其余部分重复使用它,因为我缺少类,所以无法编译代码)。
class Example有两个构造函数,每个都接受一个String?参数。但是它不能编译...

class Example {

  private var id: String? = null
  private var name: String? = null

  constructor(id: String?) {
    this.id = id
  }

  // ERROR
  // Conflicting overloads: 
  // public constructor Example(id: String?) defined in Example, 
  // public constructor Example(name: String?) defined in Example
  constructor(name: String?) {
    this.name = name
  }
}

这与您看到的错误不同。
class SlideModel中的构造函数不同,class Example中的构造函数不是唯一的。参数的名称被忽略了,所以编译器看到的只是两个相同的构造函数--这是被禁止的。

冲突的泛型构造函数

此外,由于类型擦除,JVM编译器无法根据泛型类型进行区分。例如,List<String>List<Int>在编译后看起来是一样的,所以同样,您不可能有两个看起来相同的构造函数。

class ExampleLists {

  private var ids: List<Int>? = null
  private var names: List<String>? = null

  constructor(ids: List<Int>) {
    this.ids = ids
  }

  // ERROR
  // Platform declaration clash: 
  // The following declarations have the same JVM signature (<init>(Ljava/util/List;)V):
  //    constructor ExampleLists(ids: List<Int>) defined in ExampleLists
  //    constructor ExampleLists(names: List<String>) defined in ExampleLists
  constructor(names: List<String>) {
    this.names = names
  }
}

这与您看到的错误相同。
正如@Zoe所指出的,这种行为已经在这里得到了回答:Kotlin thinks that two methods have the same JVM signature, but the actually don't

溶液

@JvmName静态方法构造函数(& S)

因为它是一个构造函数,所以不能直接使用@JvmName注解来提供帮助。

// ERROR
  // This annotation is not applicable to target 'constructor'
  @JvmName("idConstructors") 
  constructor(ids: List<Int>) {
    this.ids = ids
  }

但是,您可以在配套对象中创建一些类似于构造函数、伪构造函数的函数。

// The 'faux constructors' must be imported
import ExampleLists.Companion.ExampleLists

class ExampleLists {

  private var ids: List<Int>? = null
  private var names: List<String>? = null

  companion object {

    /**Faux constructor - creates [ExampleLists] and sets [ExampleLists.ids] */
    @JvmName("exampleListsIds") // manually set JvmName, so each 'constructor' doesn't clash
    fun ExampleLists(ids: List<Int>): ExampleLists {
      val instance = ExampleLists()
      instance.ids = ids // only set ids
      return instance
    }

    /**Faux constructor - creates [ExampleLists] and sets [ExampleLists.names] */
    @JvmName("exampleListsNames") // manually set JvmName
    fun ExampleLists(names: List<String>): ExampleLists {
      val instance = ExampleLists()
      instance.names = names // only set names
      return instance
    }
  }

  override fun toString() = "ExampleLists(ids=$ids, names=$names)"

}

fun main() {
  println(ExampleLists(listOf("test"))) 
  // prints: ExampleLists(ids=[], names=[test])
  println(ExampleLists(listOf(1)))
  // prints: ExampleLists(ids=[1], names=[])
}

但是我不认为这是伟大的。它是如此多的代码!它是笨重的,难以伸缩和适应。

具有默认值的单个构造函数

因为Kotlin有重载和默认参数,并且在这个示例中您的字段默认为null,所以我建议您只需要一个(默认)构造函数。

class ExampleLists(
  private var ids: List<Int>? = null,
  private var names: List<String>? = null,
) {
  override fun toString() = "ExampleLists(ids=$ids, names=$names)"
}

fun main() {
  println(ExampleLists(names = listOf("test")))
  // prints: ExampleLists(ids=[], names=[test])
  println(ExampleLists(ids = listOf(1)))
  // prints: ExampleLists(ids=[1], names=[])
}

更好-更小,紧凑,更清晰,并利用伟大的Kotlin功能。

相关问题