Kotlin - 无法创建两个具有不同列表类型参数的构造函数

Leo*_*ela 5 java generics jvm kotlin

我试图创建以下类:

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


但是,我收到一条错误消息:

平台声明冲突:以下声明具有相同的 JVM 签名( (Ljava/util/List;)V):


我知道它们都是 List 对象,但它们是用泛型键入的,所以我确信这不会有问题。

Lin*_*ica 7

您会遇到这个问题,因为在 Java 中存在称为类型擦除的东西。并且因为 kotlin 使用 JVM,所以它也受此限制的影响。给 TL;DR;

泛型类型保留在.class文件中,因此 java 知道该类(在您的情况下List)是泛型的。但它无法跟踪实例的泛型类型。因此,实例List<Foo>List<Bar>都在运行时以其原始类型形式处理(List )。请记住,泛型仅在编译时使用以确保类型安全。

为了克服这个限制,您可以在 kotlin 中使用运算符重载。我们正在研究的运算符是()让您调用任何实例的运算符。通过使用 acompanion object我们甚至可以使它 invoke看起来像一个构造函数,并像一个 ( MyClass())一样被调用。您的代码可能如下所示:

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

这允许您像这样简单地调用它:

val mc1 = MyClass(foos) // calls constructor
val mc2 = MyClass(bars) // calls companion.invoke
Run Code Online (Sandbox Code Playgroud)