07-型变
8.2.2 型变
在Java的类型系统中,通配符类型是比较难理解的概念之一。Java将通配符分为通配符上限和通配符下限,通配符上限是指参数只能是某个类或该类型是其父类,使用关键字extend来修饰;而通配符下限指的是参数只能是某个类型或该类型的子类,使用关键字super来修饰。
根据Java官方文档的介绍,使用限制通配符虽然可以提升API的灵活性,但是泛型是不可型变的,这也就意味着List
List<String> strs = new ArrayList<String>();
List<Object> objs = strs; //编译不通过
//等价于
List<Object> objs= new ArrayList<String>();
从上面的代码可以看出,List\
public interface Collection<E> extends Iterable<E> { … }
Java作为一门类型安全编程语言,任何被编译器所接收的类型都必须是类型安全的,也就是说Java的编译器会在编译期间进行类型检查,以确保运行期间不会有任何的类型错误。List的这种定义关系,会使下面的操作无法完成,尽管这样的操作是绝对安全的。
void copyAll(Collection<Object> to, Collection<String> from) {
to.addAll(from); //编译错误,因为Collection<String>不是Collection<Object>的子类型
}
为了解决上面的问题,Java提出了通配符(?)这一概念。例如,Collection接口中的addAll()的定义如下。
interface Collection<E> …… {
void addAll(Collection<? extends E> items);
}
通配符类型参数“? extends E”表示该方法接受E类型或者E类型的一些子类型,而不仅仅只是E类型本身。这意味着,使用通配符可以有效地解决Collection\
Kotlin抛弃了通配符类型这一概念,转而引入了生产者和消费者的概念,其中,生产者表示那些只能【读取】数据的对象,使用表达式“out T”标记;消费者表示那些只能【写入】数据的对象,使用表达式“in T”标记。为了便于理解,可以简单地将“out T”理解为“? extends T”,将“in T”理解为“? super T”。