Flutter Dart:泛型的协变与逆变
本文字数:16281 字
预计阅读时间 41 分钟
一、Dart泛型
1、泛型类型省略
2、真伪泛型
二、泛型关系:协变,逆变和不变
1、类和类型,子类和子类型
定义一个非泛型类 Class Person,那么就会有个Person类型。
定义一个非泛型类 Class Boy extend Person类,会有个Boy类型
Boy就是Person的子类,Person 是 Boy类的父类。Boy是Person的子类和子类型。 List<E>类可以衍生出很多类型,这些类型之间都不是子类关系,但可能是子类型关系。如 List<int>不是List<num>的子类,但是List<int>是List<num>的子类型(Dart默认支持协变,后面会讲)。
List<E>是Iterable<E>的子类,但因为List<E>不是一种类型,所以List<E>和Iterable<E>不是子类型关系。
2、类型关系的定义与意义
f(*)是 协变 (covariant)的,当A<B时有f(A)<f(B)成立; f(*)是 逆变 (contravariant)的,当A<B时有f(B)<f(A)成立; f(*)是 不变 (invariant)的,当A<B时,f(A)与f(B)相互之间没有继承关系。
ArrayList<? extends Number>这种形式的泛型是 支持协变的 ,它可以被赋值为ArrayList<Number>、ArrayList<Integer>,但是不能被赋值为ArrayList<Object>
ArrayList<? super Number>这种形式的泛型是 支持逆变的 ,它可以被赋值为ArrayList<Number>、ArrayList<Object>,但是不能被赋值为ArrayList<Integer>
ArrayList<Number>这种形式的泛型是 不变的 ,就是说ArrayList<Number> list,不能被赋值为ArrayList<Integer>,也不能被赋值为ArrayList<Object>,只能被赋值为ArrayList<Number>
对于Class1来说,是支持多态的,比如 Collection <Integer> collect = new ArrayList <Integer>(); 对于Class2来说,有两个维度去理解:
(1)Class2本身是支持多态的,比如ArrayList<Integer)、 list.add(Double);
Number> list, 这个list可以add任何Number子类的对象,如 list.add(
3、多态的实现和限制
ArrayList<Number> list1 = new ArrayList<Number>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
list1 = list2;// 编译错误!
ArrayList<? extends Number> list1 = new ArrayList<Number>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
list1 = list2;
Number a = list1.get(0);
list1.add(1) // 编译错误!
Integer < Number
ArrayList<Integer> < ArrayList<? extends Number>
ArrayList<? super Number> list1 = = new ArrayList<Number>();
ArrayList<Object>list2=new ArrayList<Object>();
list1 = list2;
Number a = list1.get(0);// 编译错误!
list1.add(1);
Number < Object
ArrayList<? super Number> > ArrayList<Object>
4、协变和逆变的应用和实践
addAll函数中的参数c是作为生产者,从自身读取元素提供给ArrayList。通过协变参数Collection<? extends E> 中读取的元素肯定是ArrayList中元素E的子类型,子类型放进数组中肯定是支持的。 forEach函数中的参数action则是作为消费者,从ArrayList拿取元素提供给给自己使用。在array3.forEach(comsumerPerson) 中,Consumer<Person>是Consumer<? super Girl>的子类型,可以作为参数传入,comsumerPerson拿到array3的Girl元素,在accept函数中统计Person名字含“g”的人员数。这样comsumerPerson的函数功能就得到了很好的复用。
三、Dart协变
四、Dart协变安全
五、Dart协变关键字convariant
六、总结
泛型是为了功能复用,减少模板代码而提出来的一种设计思想。