# 说透泛型

泛型是属于编译器阶段的,在编译期泛型会被擦除,被称为泛型擦除机制

# 通配符

使用泛型时,Java允许使用通配符,有以下形式:

  1. <? super T>
  2. <? 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

修改于: 8/11/2022, 3:17:56 PM