其實 Kotlin 中的 out
用意,也就是 Java 中的 <? extends T>
Java 中的 <? extends T>
表示型別必須是T或T的子類別,T是上界,沒有下界。
這段話到底是什麼意思呢...?
來看一段程式碼,子類別 Cat 繼承了 Animal
Animal a = new Animal();
建立了一個 Animal 的物件
Animal b = new Cat();
因為 Cat 是子類別,所以 new Cat()
的實作給予 Animal b
是沒有問題的。
也就是在 Cat
會是 Animal
的 subtype(子類型)
public class Animal {
}
public class Cat extends Animal{
}
Animal a = new Animal();
Animal b = new Cat();
但如果今天是把Cat
Animal
放在 List 裡面呢?
發現一樣的類似的寫法,透過 List 來建立時,卻反而不行了!
所以這裡我們可以說 List<Cat>
不是 List<Animal>
的 subtype(子類型)
covariant
(型變)那通常要達到這樣的目的,就會改成如下
List<? extends Animal> cats = new ArrayList<Cat>();
這樣就可以幫我們做到,如果 Cat
是 Animal
的 subtype(子類型), 則 List<Cat>
也會是 List<Animal>
的 subtype(子類型),這件事就是所謂的 covariant
(型變)
上面的就是 Java 中的寫法,而在 Kotlin 中就會變成是這樣寫
List<? extends Animal>
會變成 List<out Animal>
var cats: List<out Animal> = listOf<Cat>()
但實際上到 Kotin 寫的時候,會發現下面這樣寫也不會錯,為什麼??
var cats: List<Animal> = listOf<Cat>()
原因就是因為 List 的原始碼就有幫我們加上 out 了,所以不會用這個問題,而且 List 是個泛型。
(待補...
那泛型中的 in,其實也就是 out 的相反,先這樣,之後再補上
(待補...
其實 Kotlin 中的 * 星號,也就是 Java 中的 <?>
(待補...
有時候我們會想要知道泛型到底是什麼型別
像是下面這個程式,想要知道傳入的泛型物件,型態是不是是 Button 型別
fun <T> checkType(obj: T) {
val button = Button("button")
if (button is T) {
println("it's button")
}
}
發現是不可行的,提示是不能對 erased type : T
做型別檢查
這裡要提到泛型是怎麼實作的,泛型在 JVM 上通常透過 type erasure 實作,也就是泛型在 runtime 時, 型別
其實是不會保留的
inline
以及 <reified T>
使用 inline
以及 <reified T>
就能為我們在 runtime 的時候也把型態保存下來,也就可以做比對了!
inline fun <reified T> checkType(obj: T) {
val button = Button("button")
if (button is T) {
println("it's button")
}
}
這裡可以注意到,為什麼還要搭配 inline
呢? 如之前提到過的 宣告成 inline 的 function compiler 會把 bytecode 塞到每個有呼叫這個 inline function 的地方,所以 compiler 也就知道呼叫的地方是使用什麼型態呼叫這個 inline function!所以型態也就保留下來了。
以上就是今天的內容!謝謝大家!今天還有些內容還沒補上...明天再補吧