Scala11——協變、逆變、非變以及上下界
協變、逆變、非變介紹
協變和逆變主要是用來解決引數化型別的泛化問題。Scala的協變與逆變是非常有特色的,完全解決了Java中泛型的一大缺憾;舉例來說,Java中,如果有 A是 B的子類,但 Card[A] 卻不是 Card[B] 的子類;而 Scala 中,只要靈活使用協變與逆變,就可以解決此類 Java 泛型問題; 由於引數化型別的引數(引數型別)是可變的,當兩個引數化型別的引數是繼承關係(可泛化),在Java中這種情況下,那被引數化的型別是不可泛化的,然而Scala提供了三個選擇,即協變(“+”)、逆變(“-”)和非變。 下面說一下三種情況的含義,首先假設有引數化特徵Queue,那它可以有如下三種定義。 (1) trait Queue[T] {} 這是非變情況。這種情況下,當型別B是型別A的子型別,則Queue[B]與Queue[A]沒有任何從屬關係,這種情況是和Java一樣的。 (2) trait Queue[+T] {} 這是協變情況。這種情況下,當型別B是型別A的子型別,則Queue[B]也可以認為是Queue[A]的子型別,即Queue[B]可以泛化為Queue[A]。也就是被引數化型別的泛化方向與引數型別的方向是一致的,所以稱為協變。 (3) trait Queue[-T] {} 這是逆變情況。這種情況下,當型別B是型別A的子型別,則Queue[A]反過來可以認為是Queue[B]的子型別。也就是被引數化型別的泛化方向與引數型別的方向是相反的,所以稱為逆變。 總結:
class Dog class Xiaogou extends Dog class Animals[+T](name: String)//協變 class Animals2[-T](name:String)//逆變 class Animals3[T](name:String)//非變 object Test{ def main(args: Array[String]): Unit = { val a1:Animals[Dog]=new Animals[Xiaogou]("小狗是Dog") //val a2:Animals2[Dog]=new Animals2[Xiaogou]("小狗報錯啦") val a2:Animals2[Xiaogou]=new Animals2[Dog]("Dog是小狗") //type mismatch,編譯報錯 //val a3:Animals3[Xiaogou]=new Animals3[Dog]("xiaogou又報錯了") } }
上界、下界介紹
在指定泛型型別時,有時需要界定泛型型別的範圍,而不是接收任意型別。 例如,要求某個泛型型別,必須是某個類的子類,這樣在程式中就可以放心的呼叫父類的方法,程式才能正常的使用與執行。此時,就可以使用上下邊界Bounds的特性; Scala的上下邊界特性允許泛型型別是某個類的子類,或者是某個類的父類;
(1) U >: T ? super T
這是型別下界的定義,也就是U必須是型別T的父類(或本身,自己也可以認為是自己的父類)。
(2) S <: T ? extends T
這是型別上界的定義,也就是S必須是型別T的子類(或本身,自己也可以認為是自己的子類)。