1.1. 協變、逆變、非變介紹ide
協變和逆變主要是用來解決參數化類型的泛化問題。Scala的協變與逆變是很是有特點的,徹底解決了Java中泛型的一大缺憾;舉例來講,Java中,若是有 A是 B的子類,但 Card[A] 卻不是 Card[B] 的子類;而 Scala 中,只要靈活使用協變與逆變,就能夠解決此類 Java 泛型問題;scala
因爲參數化類型的參數(參數類型)是可變的,當兩個參數化類型的參數是繼承關係(可泛化),那被參數化的類型是否也能夠泛化呢?Java中這種狀況下是不可泛化的,然而Scala提供了三個選擇,即協變(「+」)、逆變(「-」)和非變。code
下面說一下三種狀況的含義,首先假設有參數化特徵Queue,那它能夠有以下三種定義。繼承
(1) trait Queue[T] {}it
這是非變狀況。這種狀況下,當類型B是類型A的子類型,則Queue[B]與Queue[A]沒有任何從屬關係,這種狀況是和Java同樣的。ast
(2) trait Queue[+T] {}
這是協變狀況。這種狀況下,當類型B是類型A的子類型,則Queue[B]也能夠認爲是Queue[A]的子類型,即Queue[B]能夠泛化爲Queue[A]。也就是被參數化類型的泛化方向與參數類型的方向是一致的,因此稱爲協變。class
(3) trait Queue[-T] {}泛型
這是逆變狀況。這種狀況下,當類型B是類型A的子類型,則Queue[A]反過來能夠認爲是Queue[B]的子類型。也就是被參數化類型的泛化方向與參數類型的方向是相反的,因此稱爲逆變。object
1.2. 協變、逆變、非變總結總結
Ø C[+T]:若是A是B的子類,那麼C[A]是C[B]的子類。
Ø C[-T]:若是A是B的子類,那麼C[B]是C[A]的子類。
Ø C[T]: 不管A和B是什麼關係,C[A]和C[B]沒有從屬關係。
1.3. 案例
package cn.itcast.scala.enhance.covariance class Super class Sub extends Super //協變 class Temp1[+A](title: String) //逆變 class Temp2[-A](title: String) //非變 class Temp3[A](title: String) object Covariance_demo{ def main(args: Array[String]) { //支持協變 Temp1[Sub]仍是Temp1[Super]的子類 val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!") //支持逆變 Temp1[Super]是Temp1[Sub]的子類 val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!") //支持非變 Temp3[Super]與Temp3[Sub]沒有從屬關係,以下代碼會報錯 //val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!") //val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!") println(t1.toString) println(t2.toString) } }