iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Software Development

Kotlin 島深度之旅 30 天系列 第 24

[Day 24] Kotlin Journey - Generic (泛型) : out, in, star-projections, reified

  • 分享至 

  • xImage
  •  

out

其實 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 會是 Animalsubtype(子類型)

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(子類型)

https://ithelp.ithome.com.tw/upload/images/20201003/201299027c6hkn5sMR.png

covariant (型變)

那通常要達到這樣的目的,就會改成如下

List<? extends Animal> cats = new ArrayList<Cat>();

這樣就可以幫我們做到,如果 CatAnimalsubtype(子類型), 則 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 是個泛型。

https://ithelp.ithome.com.tw/upload/images/20201003/20129902dc36Eto6Qy.png

(待補...

in

那泛型中的 in,其實也就是 out 的相反,先這樣,之後再補上

(待補...

星號 (*)

其實 Kotlin 中的 * 星號,也就是 Java 中的 <?>

(待補...

reified (具體型別)

有時候我們會想要知道泛型到底是什麼型別

像是下面這個程式,想要知道傳入的泛型物件,型態是不是是 Button 型別

fun <T> checkType(obj: T) {
    val button = Button("button")
    if (button is T) {
        println("it's button")
    }
}

發現是不可行的,提示是不能對 erased type : T 做型別檢查

https://ithelp.ithome.com.tw/upload/images/20201003/20129902M15pf0TzDo.png

這裡要提到泛型是怎麼實作的,泛型在 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!所以型態也就保留下來了。

以上就是今天的內容!謝謝大家!今天還有些內容還沒補上...明天再補吧


上一篇
[Day 23] Kotlin Journey - Generic (泛型) 基礎
下一篇
[Day 25] Kotlin Journey - Extension (擴充)
系列文
Kotlin 島深度之旅 30 天31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言