协变:在期望接收一个基类集合的地方使用子类实例集合的能力
逆变:在期望接收一个子类集合的地方使用基类实例集合的能力
在默认情况下,scala不允许使用协变和逆变,称之为不变
举个例子:我们定义两个class,一个是Pet,一个是Dog,让Dog继承自Pet。
然后我们调用一个方法,在接Array[Pet]的地方传入Array[Dog]
在标红处,会提示type mismatch,说明默认情况不支持协变。
但是,我们可以通过特殊的语法来支持协变。
这里T <: Pet 表示T派生自Pet,Pet为T的上界,传入数组至少得是Array[Pet],或者其子类集合。
反之,也可以支持逆变,在接收子类集合的地方传入基类集合
这里Dog是T的下界。
前面介绍的,都是在方法参数做的型变。如果我们需要自定义数据格式的话,我们也可以使用”+T”或者“-T”来支持协变和逆变。
举个例子,前面我们定义的pets和dogs。
如果直接赋值的话,会提示type mismatch。
我们自己定义一个Array,“+T”表示支持协变。
petArray期望接收一个MyArray[Pet],但是接收了MyArray[Dog]。
反之,“-T”支持逆变
完整代码
object test extends App { def workWithPet(pets:Array[Pet]): Unit ={ } var dogs = Array[Dog](new Dog("bill"), new Dog("bob")) // workWithPet(dogs) def workWithPet2[T <: Pet](pets:Array[T]): Unit ={ } workWithPet2(dogs) var pets = Array[Pet](new Pet("bill"), new Pet("bob")) def workWithPet3[T >: Dog](dogs:Array[T]): Unit ={ } workWithPet3(pets) // pets = dogs // dogs = pets var dogArray = new MyArray[Dog]() var petArray = new MyArray[Pet]() petArray = dogArray var dogArray2 = new MyArray2[Dog]() var petArray2 = new MyArray2[Pet]() dogArray2 = petArray2 } class MyArray[+T]{ } class MyArray2[-T]{ } class Pet(name: String) { override def toString: String = name def behavior(): Unit = { println("This is a Pet.") } } class Dog(name: String) extends Pet(name: String) { override def toString: String = name override def behavior(): Unit = { println("This is a Dog.") } }