协变和逆变
思考一个问题,如果Professional是Master的子类,那么对于一个带类型参数的类型,比如Card[Professional]是不是Card[Master]的子类呢? 在JAVA里,不是的。因此在程序开发中,有时会造成一些麻烦。而Scala中,只要灵活使用协变和逆变,就可以解决Java泛型的问题。
通过一个老师进入会场的案例来讲解协变和逆变:
定义三个类,SeniorTeacher>MiddleTeacher>JuniorTeacher。
class JuniorTeacher extends MiddleTeacher{}
class MiddleTeacher extends SeniorTeacher{}
class SeniorTeacher {}
现在已知,中级老师可以进入会场。也就是enterMeeting的参数是Card[MiddleTeacher]。
class Card[+T](val name:String) {
def enterMeeting(card: Card[MiddleTeacher]): Unit = {
println(card.name +"you can enter")
}
}
那么我如果希望初级老师可以进入会场,即我希望中级的子类可以进入会场,该怎么办??—>答案:协变
如果我希望高级老师可以进入会场,即我希望中级的父类可以进入会场,该怎么办??—>答案:逆变
协变
假设A的子类是B,List[B]也是List[A]的子类。也就是被参数化类型的泛化方向与参数类型的方向是一致的,就称为协变。
此列中,MiddleTeacher的子类是JuniorTeacher,那么Card[JuniorTeacher]也是Card[MiddleTeacher]的子类,就称为协变,用+T表示。
/**
* 协变 (+T)
* 中级及中级以下的老师,可以进入会场
*/
class Card[+T](val name:String) {
def enterMeeting(card: Card[MiddleTeacher]): Unit = {
println(card.name +"you can enter")
}
}
object Card{
def main(args: Array[String]): Unit = {
var zhangsan = new Card[JuniorTeacher]("zhangsan")
var lisi = new Card[MiddleTeacher]("lisi")
var wangwu = new Card[SeniorTeacher]("wangwu")
zhangsan.enterMeeting(zhangsan)
lisi.enterMeeting(lisi)
// wangwu.enterMeeting(wangwu) 高级老师无法进入会场
}
}
逆变
假设A的子类是B,List[B]却是List[A]的父类。也就是被参数化类型的泛化方向与参数类型的方向是相反的,即与原来的父子关系正相反,就称为逆变。
此列中,SeniorTeacher的子类是MiddleTeacher,可Card[MiddleTeacher]是Card[SeniorTeacher]的父类,就称为逆变,用-T表示。
/**
* 逆变 (-T)
* 中级及中级以上的老师,可以进入会场
*/
class Card[-T](val name:String) {
def enterMeeting(card: Card[MiddleTeacher]): Unit = {
println(card.name +"you can enter")
}
}
object Card{
def main(args: Array[String]): Unit = {
var zhangsan = new Card[JuniorTeacher]("zhangsan")
var lisi = new Card[MiddleTeacher]("lisi")
var wangwu = new Card[SeniorTeacher]("wangwu")
// zhangsan.enterMeeting(zhangsan) 初级老师无法进入会场
lisi.enterMeeting(lisi)
wangwu.enterMeeting(wangwu)
}
}
BDStar原创文章。发布者:Liuyanling,转载请注明出处:http://bigdata-star.com/archives/1657