zl程序教程

您现在的位置是:首页 >  Java

当前栏目

Java中泛型extends与super的区别

2023-02-26 10:21:29 时间

从泛型说起
1.Java从1.5开始引入了泛型,泛型-也就是参数化类型。在Java容器类中大量的使用了泛型这种思想。泛型的利用好处很多:

减少了代码中大量的强制性类型转换,可读性更高
通用性更强,
类型更安全,提高性能等

2.需要明确的是Java的泛型是伪泛型,泛型只在编译时期有效,在编译器正确的检验出泛型的结果后随即泛型的信息就会被擦除。并且泛型的信息不会进入到运行时阶段。看一个例子:

(福利推荐:阿里云、腾讯云、华为云服务器最新限时优惠活动,云服务器1核2G仅88元/年、2核4G仅698元/3年,点击这里立即抢购>>>

public static void main(String[] args) {       List<Integer> integers = new ArrayList<>();      integers.add(1);       List<String> strings = new ArrayList<>();      strings.add("1");       System.out.println(integers.getClass().equals(strings.getClass())); }

3.泛型信息被擦除成原始的List,在实际开发中,泛型擦除会带来一些问题,既然运用了无界泛型,并且由于泛型擦除的存在,那么只能调用Object的自身方法。这个时候我们就需要给泛型指定边界,将泛型限制在一定的范围。

上界通配符<? extends T>

1.上界,顾名思义,最高只能到T,也即类型只能是T或者是T的子类。以水果这个常见的类型举例,水果,热带水果,苹果,橘子,香蕉等。可见水果作为整个超类依次往下。

public class Fruit {}  public class TropicalFruit extends Fruit {/** 热带水果 */}  public class Apple extends TropicalFruit {}  public class RedApple extends Apple {}  public class Orange extends TropicalFruit {}  public class Banana extends TropicalFruit {}

2.拿集合List举例:

public static void main(String[] args) {     List<? extends TropicalFruit> appleList = new ArrayList<>();     //报错,提示无法添加     appleList.add(new Apple());     appleList.add(null); }

3.之前提到<? extends T>上界通配符规定的是最高到T类型,而我们这里List<? extends TropicalFruit>为什么不能够添加Apple呢?null是可以的,因为null表示任何类型。这里定义了一个装热带水果(TropicalFruit)的集合,按理说苹果(Apple)是可以放进去的,这是对于概念混淆可能会犯这样的错误。其实这里很好理解,首先编译器其实不聪明,List<? extends TropicalFruit>编译器理解的是,只要是热带水果本身或者其子类都是可以存放的,那么问题来了,假如是一个List,此时我想放香蕉那显然是不行的。类型转化错误,但是编译器知道的是都是热带水果TropicalFruit,有可能是装苹果的袋子,也有可能是装香蕉的袋子,具体是不知道的,那么添加操作显然是不安全的。索性编译时期直接报错。

下界通配符<? super T>

1.同样的:

public static void main(String[] args) {     List<? super Apple> appleList = new ArrayList<>();     appleList.add(new Apple());     appleList.add(new RedApple());     appleList.add(null);     //报错,无法通过编译     appleList.add(new TropicalFruit()); }

2.还是一样的问题,既然规定存放的是Apple以及它的超类,那么TropicalFruit是符合要求的,为什么却无法添加?

3.类比上届通配符,<? super T>集合中保存的是T以及T的父类,编译器是不知道具体的类型的(有可能是直接父类,有可能是超类),有可能是List、List。例子中的代码

List<? super Apple> 存放的是Apple,那么Apple,RedApple都是可以添加的

这样可以添加的原因,想想多态的概念,向上转型是安全的操作(子类的对象赋值给父类的引用),存放的Apple可以向上转型为TropicalFruit、Fruit,Object,如果存入Fruit显然涉及向下强制类型转化,可是编译器判断不了,因为可能是List或者List,也即下界其实定义最小能添加的元素类型T或者T的子类(向上转型属于安全操作)。

4.extends可用于的返回类型限定,不能用于参数类型限定。super可用于参数类型限定,不能用于返回类型限定。

PECS原则

1.如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends->PE)。
2.如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super->CS)。
3.如果既要存又要取,那么就不要使用任何通配符。

Java中泛型extends与super的区别


本站部分内容转载自网络,版权属于原作者所有,如有异议请联系QQ153890879修改或删除,谢谢!
转载请注明原文链接:Java中泛型extends与super的区别

你还在原价购买阿里云、腾讯云、华为云、天翼云产品?那就亏大啦!现在申请成为四大品牌云厂商VIP用户,可以3折优惠价购买云服务器等云产品,并且可享四大云服务商产品终身VIP优惠价,还等什么?赶紧点击下面对应链接免费申请VIP客户吧:

1、点击这里立即申请成为腾讯云VIP客户

2、点击这里立即注册成为天翼云VIP客户

3、点击这里立即申请成为华为云VIP客户

4、点击这里立享阿里云产品终身VIP优惠价

喜欢 (0)
[[email protected]]
分享 (0)