Scala协变、逆变

先来看看Java中泛型上下界的例子:

        List covariantList;

        covariantList = new ArrayList(); //wrong
        covariantList = new ArrayList(); //right
        covariantList = new ArrayList(); //right
        //类似于Scala中的协变,即,如果A是T的子类,那么List是List的子类

        covariantList.add(new Integer(1)); //wrong
        covariantList.add(new Long(1));//wrong
        covariantList.add(new Object());//wrong
        covariantList.add(null); //right
        //Java为了保护类型一致(因为List实例可能是List也有可能是List),所以禁止向中添加任何对象,除了null。

        Number a = covariantList.get(0); //right
        Integer b = covariantList.get(0); //wrong
        //另外,只能以最宽泛的方式获取List元素
        List contravariantList;

        contravariantList = new ArrayList(); //right
        contravariantList = new ArrayList(); //right
        contravariantList = new ArrayList(); //wrong
        //类似于Scala中的逆变,即,如果A是T的父类,那么List是List的子类

        contravariantList.add(new Integer(1)); //OK
        contravariantList.add(new Double(1)); //OK
        contravariantList.add(new Object()); //wrong
        //不管实例是何种List实例,但肯定是Number或者是其父类,所以可以添加子类(Integer、Double)
        
        Number c = contravariantList.get(1); //wrong
        Object d = contravariantList.get(2); //right
        //同样也只能以最宽泛的方式获取List元素

Scala中的协变、逆变
对于泛型类C[+T],现在有具体类型A、B,如果B是A的子类,那么C[B]也是C[A]的子类,我们称这个类C支持协变。相反,C[-T]则称之为逆变
当我们定义一个协变类型List[A+]时,List[Child]可以是List[Parent]的子类型。
当我们定义一个逆变类型List[-A]时,List[Child]可以是List[Parent]的父类型。

class Person
class Student extends Person
class C[+T](val args: T)
class S[+T](arg : T) extends C[T](arg) //对于子类,同样要支持协变或者逆变
trait Friend[-T]{
  def makeFriend(somebody: T)
}

object Variance {
  def makeFriendWithYou(s: Student, f: Friend[Student]){f.makeFriend(s)}
  def main(args: Array[String]) {
    val value : C[Person] = new C[Student](new Student)

// List list = new ArrayList()
    val list : List[_ <: Any] = List[String]("Spark")
  }
}

推荐阅读更多精彩内容