Reputation: 49
I was trying to create a class
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
}
}
However, I got an error saying
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
I saw in a library doing exactly the same without error.
Edit: That other library is below:
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
}
}
I'm creating a recycler view with multiple recyclerviews in it. So this class becomes a model class for that recyclerview and I want it to call viewType and differnet list from other model classes. Thank you
Upvotes: 2
Views: 1105
Reputation: 7110
The example you provide, class SlideModel
, has multiple constructors. Each constructor has a unique combination of parameter types. That's important - because Kotlin gets turned into Java, and in Java, the names of the parameters get ignored. The JVM compiler just doesn't care about the names - all it cares about is the order of the parameter types.
Let's have a look at a simpler example (which I'll re-use for the rest of this answer, as I'm missing classes so I can't compile your code).
class Example
has two constructors, each accepting a String?
parameter. But it doesn't compile...
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
}
}
This is a different error to the one you're seeing.
Unlike the constructors in class SlideModel
, the constructors in class Example
are not unique. The names of the parameters are ignored, and so all the compiler sees is two identical constructors - which is forbidden.
Furthermore, because of type erasure, the JVM compiler can't distinguish based on generic types. For example, List<String>
and List<Int>
look the same after compilation, so again, you can't have two constructors that appear the same.
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
}
}
This is the same error you're seeing.
As @Zoe noted, this behaviour has been answered here: Kotlin thinks that two methods have the same JVM signature, but the actually don't
@JvmName
& static method constructorsBecause it's a constructor, you can't directly use the @JvmName
annotation to help.
// ERROR
// This annotation is not applicable to target 'constructor'
@JvmName("idConstructors")
constructor(ids: List<Int>) {
this.ids = ids
}
You can, however, create some functions that act like constructors, faux constructors, in a companion object.
// 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=[])
}
However I don't think this is great. It's so much code! It's clunky and difficult to scale and adapt.
Because Kotlin has overloads and default parameters, and your fields are defaulting to null in this instance, I suggest you only need one (default) constructor.
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=[])
}
Much better - smaller, compact, clearer, and utilises great Kotlin features.
Upvotes: 1