本文介绍: 泛型只是程序员和的约定。我们可以通过泛型告诉编译器自己的呐,我现在假定这个List只能存String,你帮我盯着点,后面如果不小心放错类型,在提醒我。就好比Spring明明告诉你默认读取resources/application.yml,你非要把配置文件命名resources/config.yml当然就报错啦。而泛型也有一套自己的规则我们必须遵守这些规则才能让编译器按我们的意愿做出约束。这些规则是谁定的呢?当然是JDK的那群秃子咯。今天我们来学习泛型通配符。

作者简介大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

我们花了两篇文章讲述了泛型是什么以及有什么用:

泛型只是程序员和编译器的约定。

我们可以通过泛型告诉编译器自己的意图

呐,我现在假定这个List只能存String,你帮我盯着点,后面如果不小心放错类型,在编译期报错提醒我。

  • 首先,ls.add(new Object())成功了,那就意味着之前List<String>所做的约束都白费了,因为StringList中混入了别的类型
  • 其次,编译器仍会按String自动转型,会发生ClassCastException

  • List<Number>指向:只能指向List<Number>,左右两边泛型必须一致(所以简单泛型解决不了print(List<???> list)的通用性问题
  • List<Number>存入:可以存入Integer/Long/BigDecimal…等Number子类元素
  • List<Number>取出:自动按Number转(存在多态,不会报错)

  • List<? extends Number>指向:Java允许extends指向子类型List,比如List<? extends Number>允许指向List<Integer>
  • List<? extends Number>存入:禁止存入(防止出错)
  • List<? extends Number>取出:由于指向的都是子类型List,所以按Number转肯定是正确
  • List<? super Integer>指向:只能指向父类型List,比如List<Number>、List<Object>
  • List<? super Integer>存入:只能存Integer及其子类型元素
  • List<? super Integer>取出:只能转Object
  • extends:指向子类型List
  • 简单泛型T:指向同类型List
  • super:指向父类型List

  • List<? super Human>指向:只能指向父类型List,比如List<Speaking>、List<Swimming>
  • List<? super Human>存入:只能存Human及其子类型元素
  • List<? super Human>取出:只能转Object

  • 由于指向的List不确定,并且这些List没有共同的子类,所以找不到一种类型的元素,能保证add()时百分百不出错,所以禁止存入。
  • 由于指向的List不确定,并且这些List没有共同的父类(除了Object),所以只能用Object接收。

  • 入参和泛型相关的都不能使用(禁止存入)
  • 返回值和泛型相关的都只能用Object接收(只能强转为Object)
  • extends不允许存入,但取出时类型稍微精确些,可以往边界类型转
  • super允许存入子类型元素,但取出时只能转为Object
  • 频繁往外读取内容的(向外提供内容,所以是Producer),适合用<? extends T>:extends返回值稍微精确些,调用者友好
  • 经常往里插入的(消耗数据,所以是Consumer),适合用<? super T>:super允许存入子类型元素

  1. List list = new ArrayList(); 能添加各种类型的数据吗?
  2. List<Object> list = new Array<Integer>()会报错吗?为什么?
  3. 什么时候用?、extends、super?
  4. PECS是什么?
  5. List<?>和List<Object>的区别?

作者简介大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

进群,大家一起学习,一起进步,一起对抗互联网寒冬

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注