# 说透泛型
泛型是属于编译器阶段的,在编译期泛型会被擦除,被称为泛型擦除机制。
# 通配符
使用泛型时,Java允许使用通配符,有以下形式:
- ?
- <? super T>
- <? extends T>
以上形式还有各种变种,这里不赘述。
# 取值和赋值
泛型通配符的使用对于其概念稍作了解后,使用一般是没有多大问题,但对使用了泛型通配符的对象进行取值和赋值时,很多人有会一头雾水,接下来我们介绍extends和super它们对于取值赋值的理解难点。
# <? extends T>
假设有List<? extends Number> array对象,现需要从中读取和写入值,我们来看下有什么区别。
# 读取
只能从array中获取Number对象,因为其他extends对象都会引发运行报错的可能。
# 写入
无法写入对象到array,因为其不确定性,无法确保写入的类型能匹配,依然有报错的可能。
# <? super T>
假设有List<? super Integer> array对象。
# 读取
只能从array中获取Object对象,否则其他都可能会引发报错。
# 写入
只能往array中写入Integer或其子类对象,其他都可能会引发报错。
# 使用场景
PECE 原则: Producer Extends, Consumer Super
只读用extends,只写用super
Producer extends: 如果我们需要一个 List 提供类型为 T 的数据(即希望从 List 中读取 T 类型的数据), 那么我们需要使用 ? extends T, 例如 List<? extends Integer>. 但是我们不能向这个 List 添加数据.
Consumer Super: 如果我们需要一个 List 来消费 T 类型的数据(即希望将 T 类型的数据写入 List 中), 那么我们需要使用 ? super T, 例如 List<? super Integer>. 但是这个 List 不能保证从它读取的数据的类型.
如果我们既希望读取, 也希望写入, 那么我们就必须明确地声明泛型参数的类型, 例如 List<Integer>.
# reference
https://segmentfault.com/a/1190000008423240
← 设计高性能线程安全的Java缓存 简介 →