協(xié)變 Covariance
在期望接收一個基類(父類) 實例的集合的地方,能夠使用一個子類實例的集合的能力叫做協(xié)變曙搬。
//基類
var objects: List[Any] = null;
//子類
val ints = List(1,2,3,4)
objects = ints //scala 會編譯錯誤
如上面的代碼赞别,將 int 數(shù)據(jù)類型的集合賦值給 Any 類型的集合制圈,就是協(xié)變。
Scala 的 List[+T] 支持協(xié)變
逆變 Contravariance
在期望接收一個子類實例的集合的地方,能夠使用一個基類(父類) 實例的集合的能力叫做逆變休里。
//子類
var ints: List[Int] = null;
//基類
val objects = List("3","4")
ints = objects //scala 會編譯錯誤
如上面的代碼富腊,將 objects 父類數(shù)據(jù)類型的集合賦值給 int 類型的集合坏逢,就是逆變。
Scala 的 List[+T] 不支持逆變
如何支持協(xié)變 -- 協(xié)變定義上界
定義 Pet 和 Dog
case class Pet(name: String)
case class Dog(name:String) extends Pet(name)
有一個接收 List[Pet] 的方法
def doPets(pets: List[Pet]) = {
//xxxx
}
如果使用 List[Dog] 的集合傳入該方法會報編譯錯誤赘被,如果想讓該方法支持協(xié)變是整,則可以像如下方法定義:
def doPets[T <: Pet](pets: List[T]) {
// xxxx
}
T <: Pet
表明由 T 表示的類派生自 Pet 類,也即 T 為 Pet 的子類民假。這個語法定義了一個上界浮入。Pet 為 T 的上界,即往父類方向坐了限制羊异。
如何支持逆變 -- 逆變定義下界
//逆變,限制了下界, T 必須為 Apple 或其超類
def writeTo[T >: Apple](apples: List[T]): Unit = {
}
逆變會決定下界舵盈,然后你可以在上述的 apples 中添加 Apple 或其父類。
PECS 原則
《Effective Java》給出精煉的描述:producer-extends, consumer-super(PECS)球化。
- 協(xié)變限制數(shù)據(jù)來源,生產(chǎn)者秽晚,保證生產(chǎn)的產(chǎn)品為 T 或其子類。
- 逆變限制數(shù)據(jù)消費筒愚,保證用來消費的數(shù)據(jù)必須時 T 或其父類赴蝇。
//copy方法限制了拷貝源src必須是T或者是它的子類,
// 而拷貝目的地dest必須是T或者是它的父類巢掺,這樣就保證了類型的合法性句伶。
def copy[S, D >: S](src: List[S], dest: List[D]): Unit = {
}
- copy 方法,限制 src 來源必須是 S 及其子類陆淀,限制 dest 是 S及其父類考余,這樣才能去接收。
在scala泛型中獲取其 Class[T]
需求:獲取一個泛型 T 的 class 類型的 Class[T],有兩種方法轧苫。
獲取方式1
def getClassT[T](obj: T): Class[T] = {
val res = obj.getClass.asInstanceOf[Class[T]]
res
}
更優(yōu)雅的獲取方式
def getClassT[T](obj: T)(implicit m: Manifest[T]): Class[T] = {
val res: Class[T] = m.runtimeClass.asInstanceOf[Class[T]]
res
}