一、协变与逆变的介绍
正常来说创建一个Person类,然后可以创建一个Student类继承Person来继承他。当我们创建对象的时候可以用父类类型指向子类实例。
再java中父类类型指向子类实例是可以的,当然再scala中也是可以存在的。但是如果是list[Person]那就不是list[Student]的父类了。再java中不存在协变与裂变,也就没有办法让list[Person]成为list[Student]的父类。
再scala中不仅可以让list[Person]成为list[Student]的父类,甚至可以让list[Student]成为list[Person]的父类。前者称为协变,后者称为逆变。
二、先演示和java一样的不变案例
案例说明:
- 先定义一个猫类,猫是吃鱼的。
- 在定义一个老虎类,老虎是吃肉的,但是老虎也是猫科动物的以这种,可以继承猫类
- 定义不变类。
- 用所谓的父类类型去new子类对象看看是否成功。
代码演示:
object Test {
//定义动物类
class Animal{
def eat(): Unit ={
println("动物吃东西")
}
}
//创建猫类继承动物类
class Cat extends Animal {
override def eat(): Unit = println("猫吃鱼")
}
//创建老虎类继承猫类
class Tiger extends Cat{
override def eat(): Unit = println("老虎吃肉")
}
class BuBian[T]{} //不变
//不变就是创建两个buBian[T]是没有关系的
var catBb:BuBian[Cat]=new BuBian[Cat] //对的
var catBb1:BuBian[Cat]=new BuBian[Tiger] //错的
}
三、协变代码演示
协变简单的说就是list[Cat]是list[Tiger]的父类
代码演示:
object Test {
//定义动物类
class Animal{
def eat(): Unit ={
println("动物吃东西")
}
}
//创建猫类继承动物类
class Cat extends Animal {
override def eat(): Unit = println("猫吃鱼")
}
//创建老虎类继承猫类
class Tiger extends Cat{
override def eat(): Unit = println("老虎吃肉")
}
class XieBian[+T]{} //协变
//协变就是XieBian[Cat]是XieBian[Tiger]父类
var catXb:XieBian[Cat]=new XieBian[Tiger] //这样写就是对的
}
四、逆变代码演示
逆变与协变正好反过来,list[Cat]是list[Tiger]的子类
代码演示:
object Test {
//定义动物类
class Animal{
def eat(): Unit ={
println("动物吃东西")
}
}
//创建猫类继承动物类
class Cat extends Animal {
override def eat(): Unit = println("猫吃鱼")
}
//创建老虎类继承猫类
class Tiger extends Cat{
override def eat(): Unit = println("老虎吃肉")
}
class NiBian[-T]{} //逆变
//逆变就是NiBian[Cat]是NiBian[Tiger]的子类
var tigerNb:NiBian[Tiger]=new NiBian[Cat] //这样写是对的
}
五、总结
关于scala中的协变和逆变问题,要抓住一个知识点,那就是父类类型可以指向子类实例。
而协变和逆变也就是说谁是父类的事。如果是协变那就是list[Cat]是父类,如果是逆变那就是list[Tiger]。