
最近在阅读JDK源码的时候,经常在各种类、接口或者方法上看到各种复杂的泛型写法,不能很好地理解参数这样设计的好处或者意图是什么,因此在阅读相关博客资料后做如下总结归纳。
泛型
JDK5引入的新特性,提供了编译时类型安全检测机制。- 本质是参数化类型。
- 好处是在编译时能够检查类型安全,并且所有的强制转换都是自动和隐式的。
受限泛型
有时候我们希望像使用普通类型那样使用泛型类型。
- 向上转型一个泛型对象的引用
- 向下转型一个泛型对象的引用
首先要说明的一点是,Java强制在创建对象的时候必须给类型参数制定具体的类型,不能使用通配符,比如new ArrayList<?>()或者new ArrayList<? extends A>这种。
<? extends E>
@Test
public void test1() {
//PE:Prodcer Extends
ArrayList<? extends Number> list = new ArrayList<>();
//list.add(new Integer((1))); 编译错误
Number number = list.get(0);
}
只能读取,不能写入!
调用add()会导致编译失败,是因为我们在创建实例时,可能使用了E也可能使用了E的子类,编译器无法获取准确的信息,工作无法正常进行。而对于get()方法来说,由于我们是通过E或者E的子类来创建实例,而用超类来引用子类在Java中是合法的,所以我们能通过get()方法拿到一个E类型的引用。
<? super E>
@Test
public void test2() {
//CS:Consumer Super
ArrayList<? super Apple> list = new ArrayList<>();
list.add(new Apple());
//Apple apple = list.get(0); 编译错误
}
只能写入,不能读取!
调用get()方法会导致编译失败,是因为我们在创建实例时,可能使用了E也可能使用了E的超类,当调用get()时编译器是无法知道准确信息的,而Java中超类引用子类的合法性又无法在这里得到应用(未知类的父类也是未知的)。而对于add()方法,虽然我们无法知道实例到底使用了E还是E的超类,但是我们可以确定加入E或者E的子类是没有问题的,因为超类引用子类在Java中是一个合法行为。
PECS法则
指 “Producer Extends, Consumer Super”,来自 Joshua Bloch的《Effective Java》。
换言之,生产者使用 ? extends,消费者使用 ?super。
- 如果你想要从一个数据类型里获取数据,那么使用 ? extends 通配符。
- 如果你想要把对象写入一个数据类型,那么使用 ? super 通配符。
- 如果你既想存,又想取,那就别使用泛型通配符。
本文介绍了Java泛型中的PECS原则,即Producer Extends和Consumer Super,详细解析了向上转型和向下转型泛型对象引用的限制。通过示例代码展示了? extends和? super在生产者和消费者场景中的使用,强调了泛型在编译时提供类型安全的重要性。

被折叠的 条评论
为什么被折叠?



