也許我累了,或者思維不正確,或者這只是我以前從未嘗試過的事情。
我有一個基本資料型別,我們稱之為它Foo,還有一個介面,我們稱之為它,Problem它公開了一些使用這種Foo資料型別的函式。
其中一個介面函式回傳a Foo,而其中一個函式接收a Foo。
然后,我從 , 繼承Foo來創建一個新的資料型別,我們稱之為Bar,然后我實作Problem介面,并在覆寫中,我覆寫了Footo的型別Bar。
對于回傳的函式,覆寫Foo的使用有效。Bar但是,對于接收的函式,覆寫Foo的使用Bar不起作用:
open class Foo(
open val name: String
)
interface Problem {
fun setFoo(foo: Foo)
fun getFoo() : Foo
}
data class Bar(
override val name: String
) : Foo(
name = name
)
class ProblemImpl : Problem {
override fun setFoo(foo: Bar) {
TODO("Not yet implemented")
}
override fun getFoo(): Bar {
TODO("Not yet implemented")
}
}
setFoo overrides nothing
現在,這似乎很明顯;只是不要覆寫這樣的型別!您可以只傳遞Bar實體,并且由于多型性,它們將作為Foo實體接收。但是,由于復雜的原因,我不會在這里討論,我不能這樣做(想想在庫中宣告 Dao 介面,并在使用帶有 Room 注釋的應用程式中覆寫它......)
我想我可以將介面型別引數化......比如:
interface Problem<T: Foo> {
fun setFoo(foo: T)
fun getFoo() : T
}
事實上,我想我剛剛回答了我自己的問題......我現在會嘗試使用模板,但我有預感它會在編譯時失敗,因為 Room 注釋處理器可能無法處理模板介面...... .無論如何,誰能告訴我為什么不能用子型別覆寫接收的函式而回傳的函式可以?
uj5u.com熱心網友回復:
無論如何,誰能告訴我為什么不能用子型別覆寫接收的函式而回傳的函式可以?
限制是由于Liskov 替換原則造成的:如果 Bar 是 Foo 的子型別,那么無論您在哪里使用 Foo,您都應該能夠使用 Bar。
我們來看兩種情況:
- 該函式
getFoo()回傳 Foo。在子型別中,您回傳 Bar。由于每個 Bar 都是 Foo(因為 Bar 是 Foo 的子型別),您可以在使用基本版本的每個地方使用覆寫的 getFoo() 版本 - 它總是回傳一個 Foo(恰好是 Bar,一個特定的Foo 的型別)。一切正常。 - 該函式
setFoo()接收一個 Foo。在子型別中,您希望它接受 Bar。現在,有人通過對基本型別的參考來使用您的子型別。它們傳遞給setFoo()不是 Bar 的 Foo。但setFoo()在這種情況下,您只接受 Bar。這意味著您不能使用您的子類代替基類,這違反了 Liskov 替換原則并導致子類化的整個想法崩潰。因此,語言的選擇是不允許子類接受 Bar 代替 Foo。
當子型別可以用來代替它們的超型別時,您還可以閱讀協變和逆變來更多地探索該主題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/481594.html
