[英]Kotlin - Can't create two constructors with different List types parameters
我试图创建以下类:
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)
}
}
}
但是,我收到一条错误消息:
平台声明冲突:以下声明具有相同的 JVM 签名( (Ljava/util/List;)V):
我知道它们都是 List 对象,但它们是用泛型键入的,所以我确信这不会有问题。
您会遇到这个问题,因为在 Java 中存在称为类型擦除的东西。 并且因为 kotlin 使用 JVM,所以它也受此限制的影响。 给 TL;DR;
泛型类型保留在.class
文件中,因此 java 知道该类(在您的情况下为List
)是泛型的。 但它无法跟踪实例的泛型类型。 因此实例List<Foo>
和List<Bar>
在运行时都以其原始类型形式处理( List
)。 请记住,泛型仅在编译时使用以确保类型安全。
为了克服这个限制,您可以在 kotlin 中使用运算符重载。 我们正在查看的运算符是()
,它让您可以调用任何实例。 通过使用companion object
我们甚至可以使这个invoke
看起来像一个构造函数,并且像一个构造函数一样被调用( MyClass()
)。 您的代码可能如下所示:
class MyClass(var foos: List<Foo>) {
companion object {
operator fun invoke(bars: List<Bar>) = MyClass(bars.map(::Foo))
}
}
这允许您像这样简单地调用它:
val mc1 = MyClass(foos) // calls constructor
val mc2 = MyClass(bars) // calls companion.invoke
这不是 Kotlin 问题,而是 Java 泛型的一种机制。 此机制旨在避免仍然使用原始类型的遗留代码中的冲突。
例如,如果您在 Java 中创建一个类,如下所示:
public class MyClass {
private List<Foo> foos;
MyClass(List<Foo> foos) {
this.foos = foos;
}
MyClass(List<Bar> bars) {
List<Foo> foos = new ArrayList<>();
bars.forEach(bar -> foos.add(new Foo(bar)));
this.foos = foos;
}
}
你会得到一个编译时错误,说:
'MyClass(List)' 带有 'MyClass(List)' 的类; 两种方法具有相同的擦除
类型擦除的作用是仅在编译时强制执行类型约束,并在运行时丢弃元素类型信息。 如果类型参数未绑定,则类上的类型参数在代码编译期间会被丢弃,并替换为其第一个绑定或Object
。 因此,两个构造函数(因为它们都是无界的)都属于 List,因此会出现错误。
正如其他人提到的,这是由于 Java 的类型擦除。 在某些情况下,伴随对象方法有效,但在其他情况下则不然。
如果您只有少数构造函数发生冲突,我使用的一种解决方法是利用 Java 的继承。
例如,你可以这样做:
class MyClass {
constructor(foos: Collection<Foo>) {
this.myObjects = parseFoos(foos)
}
constructor(bars: List<Bar>) {
this.instructions = parseBars(bars)
}
constructor(bazs: ArrayList<Baz>) {
this.instructions = parseBazs(bazs)
}
}
请注意参数更改( Collection
、 List
、 ArrayList
)。 您的错误应该消失了,您应该能够传入Foo
、 Bar
或Baz
ArrayList 对象,Java 将调用正确的构造函数。
同样,您只能对少数构造函数执行此操作,并且如果您愿意对调用构造函数的参数类型进行一些调整(例如,将它们声明为ArrayList
而不是List
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.