<? extends T>和<? super T>真的会用了吗?

泛型

总所周知,泛型的作用是让一段代码可以被不同类型的对象重复使用,但是最大的问题就是,每次只能放置一种类型。

如果其中随意的放置类型的话,就是 “破窗理论” ,泛型就失去了类型安全的意义。

那么我们想放多种的约束类型该怎么办?
其中有两种解决方案:

  • <? extends T>
  • <? super T>

因为只能给集合赋值,所以我个人的感觉就像是把原本的约束替换掉了,套上了层Buff。
(大佬们,如果有什么更好的比喻可以在评论区留言,小弟马上改)

在这里插入图片描述

接下来的测试以这为前提:

class A{ }
class B extends A{ }
class C extends B{ }

List<A> lista = new ArrayList<>();
List<B> listb = new ArrayList<>();
List<C> listc = new ArrayList<>();

1、<? extends T>

它可以赋值任何 T 以及 T 的子类集合,T 则为最高界限。

注意:

  • 从中取出的类型有泛型限制,所以向上强转为 T 类型。
  • 除 null 外,任何元素都不能添加进< ? extends T > 集合内。

赋值测试:

// fatherA编译出错,因为只能自身和子类集合才能赋值
List<? extends B> fatherA = lista;

List<? extends B> selfB = listb;
List<? extends B> sonC  = listc;

添加测试:

// 因为无法添加,三行添加均出错
selfB.add(new A());
selfB.add(new B());
selfB.add(new C());

取值测试:

B b  = self.get(0);
// <? extends B> 可以返回带类型的元素,只能返回B自身以及父类对象,
// 因为子类的类型被擦除了,被强转为B
B b1 = son.get(0);

使用场景:用于只往外取值,而不往里放数据的情况。

2、<? super T>

它可以赋值给任何 T 以及 T 的父类集合,T为最底界限。

注意:

  • 从中读取数据会造泛型丢失。

赋值测试:

List<? super B> fatherA = lista;
List<? super B> selfB   = listb;
// son编译出错,因为只能父类和自身集合才能赋值
List<? super B> sonC    = listc;

添加测试:

// 第一行编译出错
selfB.add(new A());
// 与extends不同,super可以添加元素,但只能添加自身和子类对象
selfB.add(new B());
selfB.add(new C());

取值测试:

// 均可获取到值,但是泛型丢失,只能返回Object对象
Object obj  = fatherA.get(0);
Object obj1 = selfB.get(0);
Object obj2 = sonC.get(0);

使用场景:适合经常的往里放东西的情况。

总结:

  • 从测试中可得出结论,extends是add受限制无法添加数据,而super是get受限制也就是泛型丢失。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/PINKMIAO/article/details/108359655