Kotlin - Can't create two constructors with different List types parameters

LeonardoSibela :

I was trying to create the following class:

class MyClass {

    var foos: List<Foo> = listOf()

    constructor(foos: List<Foo>) {
        this.foos = foos
    }

    constructor(bars: List<Bar>) : super() {
        this.foos = bars.map { bar ->
            Foo(bar)
        }
    }
}


However, I get an error saying:

Platform declaration clash: The following declarations have the same JVM signature ( (Ljava/util/List;)V):


I understand that they are both List objects, but they are typed with generics so I was sure it would not be a problem.

Lino :

You encounter this problem because in java there exists something called type erasure. And because kotlin uses the JVM it is also affected by this limitation. To give a TL;DR;

The generic type is retained in the .class file so java knows that the class (in your case List) is generic. But it can't keep track of the generic type of an instance. So instances List<Foo> and List<Bar> are both handled in their raw type form at runtime (List). Keep in mind that generics are only used at compile time to ensure type safety.

To overcome this limitation, you can make use of operator overloading in kotlin. The operator we're looking at is () which let's you invoke any instance. By using a companion object we can even make this invoke look like a constructor, and be invoked like one (MyClass()). Your code can look like this:

class MyClass(var foos: List<Foo>) {
    companion object {
        operator fun invoke(bars: List<Bar>) = MyClass(bars.map(::Foo))
    }
}

Which allows you to call it simply like this:

val mc1 = MyClass(foos) // calls constructor
val mc2 = MyClass(bars) // calls companion.invoke

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=132739&siteId=1