我在 Java 中有這個,但不知何故無法找到getStuff()在 Kotlin 中指定回傳型別的正確方法。
class Base {
}
class Extended extends Base {
}
List<? extends Base> getStuff() {
return new ArrayList<Extended>();
}
List<Extended> foo = new ArrayList<>();
foo.addAll((List<Extended>)getStuff());
當我getStuff()像這樣將函式轉換為 Kotlin 時
fun getStuff(): List<Base> { ... }
我在foo.addAll((List<Extended>)getStuff());說Java 時遇到編譯器錯誤
List<Base> 無法轉換為 List<Extended>
我發現的唯一方法是讓 getStuff() return List<*> 但這似乎不對。
uj5u.com熱心網友回復:
這似乎是 Kotlin 如何支持宣告站點差異導致的一個怪癖,但 Java 不支持。Kotlin 中的等價物<? extends Base>是<out Base>. 在 Kotlin 中,只讀 List 介面已經<out T>在宣告處,所以在使用只讀 List 時通常不需要指定out。但是當一個 List 回傳給 Java 代碼時,Java 看不到宣告站點的變體,因此它認為它是一個不變的 T。您可以在使用站點顯式地標記該變體:
fun getStuff(): List<out Base> { ... }
但是 Java 似乎仍然認為它在我的實驗中是不變的。我認為 Kotlin 不會費心應用使用站點差異,因為它在 Kotlin 方面是多余的。
在 Java 端解決這個問題的一種方法是轉換為協變型別,然后轉換為您的其他型別:
List<Extended> foo = new ArrayList<>();
foo.addAll((List<Extended>)(List<? extends Base>)getStuff());
或者,您可以將其更改為 Kotlin 中的 MutableList,這樣使用使用站點差異就不是多余的了:
fun getStuff(): MutableList<out Base> { ... }
無論哪種方式,這都是不安全的強制轉換,因為getStuff()在 Java 或 Kotlin 中回傳的 List 可能具有 Base 的子型別但不是 Extended 的元素。這可以解釋為什么 Kotlin 設計者沒有嘗試“修復”您遇到的問題。它只會啟用不安全的代碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/460189.html
上一篇:RustBook第13.1章,用泛型引數包裝HashMap
下一篇:無法為我的通用方法使用介面
