泛型最近在阅读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泛型中<? extends E>和<? super E>的区别 --博客园



