scala 泛型基础 (二)

协变逆变 

       B是A的子类,A是B的父类。 当我们定义一个协变类型List[+A]时,List[Child]可以是List[Parent]的子类型。 当我们定义一个逆变类型List[-A]时,List[Child]可以是List[Parent]的父类型。

//  java中数组是支持协变的
Number num1 = new Integer(0);
Number[] num2 = new Integer[10];
而java泛型既不支持协变也不支持逆变

List<Object> list = null; //new ArrayList<String>();//编译错误
list = new ArrayList<Object>();

但可以通过通配符?实现

List<? extends Object> list2 = new ArrayList<String>();

下面给出一个具体的例子

    List<? extends Object> covariantList = aList;
    List<? super String> contravariantList = aList;
//    covariantList.add("b"); //wrong
    Object a = covariantList.get(0);
    contravariantList.add("a"); //OK
  //  String b = contravariantList.get(1); //wrong
    Object c = contravariantList.get(0);

你可以调用covariantList所有的不需要泛型参数的方法,因为泛型参数必须 extends Object, 但是编译时你不知道它确切的类型。但是你可以调用getter方法,因为返回类型总是符合Object类型。
contravariantList正好相反,你可以调用所有的带泛型参数的方法,因为你明确的可以传入一个String的父类。但是getter方法却不行。

综上,java对协变,逆变的支持还不够强大


scala 较java最大的优势在于其函数式编程 

为我们定义了强大的trait FunctionN

 trait Function1[ -T1, +R] extends AnyRef

特质声明中参数T1是逆变的,返回值R是协变的


为了加深对协变逆变的理解 ,构造3个类

class CSuper {}

class C extends CSuper {}

class Csub extends C {}


定义函数

// trait Function1[ -T1, +R] extends AnyRef
var f: C => C = (c: C) => new C

参数C对比于-T1,返回值C 对比于+R

所以参数c应该可以看做C的父类,即对于

C => C

的接口声明参数只能是C或Csuper

而返回值C是协变的

只能是C或Csub

var f: C => C = (c: C) => new C
f = (c: CSuper) => new Csub
f=(c:C)=>new CSuper //error
f=(c:Csub)=>new C //error




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值