[英]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.