Java中List<? extends T>与List<? super T>的区别(值得珍藏)

点击下载《Java中List<? extends T>与List<? super T>的区别(值得珍藏)》

1. 名词解释

1.1 ?

?表示类型通配符,即具体传什么参数类型,在List定义时不用考虑。

1.2 <T>

这里的 <T> 表示泛型,T 表示泛型中装载的类型为T类型,等到需要的时候,我们可以具体这个 T。我们在使用动态数组实现 ArrayList 的时候,如果希望这个 ArrayList 不仅仅支持一个类型的话,我们可以给这个 ArrayList 定义泛型,泛型中存放的是T类型。在实际创建出这个 ArrayList 对象时,我们可以指定泛型中的具体类型。

1.3 <? extends T>

类型上界,这里的 ? 可以是 T 类型或者 T 的子类类型。

1.4 <? super T>

类型下界,这里的?可以是T类型或者T的超类(父类)类型,但不代表我们可以往里面添加任意超类类型的元素。

2. <? extends T>与<? super T>区别

2.1 List<? extends T>

这个通配符表示列表中的元素类型是T或T的子类。我们可以将该列表视为只读列表,因为我们只能从中读取元素,而不能添加或修改元素。这是因为编译器无法确定实际存储的元素类型。

  • 可以安全地从该列表中读取元素并将其视为T类型或T的子类类型。
  • 不能往该列表中添加任何对象,因为编译器无法确定实际存储对象的类型。

例如:

List<? extends Number> numbers = new ArrayList<Integer>();

Number number = numbers.get(0); // 读取操作
numbers.add(new Integer(10)); // 错误:无法添加 Integer 对象
public class Main {

    static class A { }

    static class B extends A { }

    static class C extends A { }

    public static void main(String[] args) {
        List<? extends A> list = new ArrayList<>();
        list.add(new A());//编译报错
        list.add(new B());//编译报错
        list.add(new C());//编译报错
    }

}

2.2 List<? super T>

这个通配符表示列表中的元素类型是T或T的父类。我们可以将该列表视为写入支持(contravariant)列表,因为我们可以向其中添加属于T或其子类的对象。但是在读取时无法确定实际存储对象类型。

  • 可以安全地向该列表中添加属于T或其子类(下界)对象。
  • 在从该列表中读取时,由于编译器无法确定实际存储对象的类型,需要进行强制类型转换。

例如:

List<? super Integer> integers = new ArrayList<Number>();

integers.add(new Integer(10)); // 添加 Integer 对象
integers.add(new Number(5.5)); // 添加 Number 对象(Number是Integer的父类)

Object object1 = integers.get(0); // 需要强制类型转换
Integer integer1 = (Integer) object1; // 强制类型转换为 Integer

Object object2 = integers.get(1); // 需要强制类型转换
Number number2 = (Number) object2; // 强制类型转换为 Number
public class Test {

    static class A { }
    
    static class B extends A { }

    static class C extends A { }

    public static void main(String[] args) {
        List<? super A> list = new ArrayList<>();
        list.add(new A());
        list.add(new B());
        list.add(new C());
    }
}

2.3 综合示例

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

public class Main {
    public static void main(String[] args) {
        // List<? extends T>
        List<? extends Animal> animals1 = new ArrayList<Animal>();
        // 编译器无法确定实际存储对象类型
        // 不能添加或修改元素
        animals1.add(null);
        Animal animal1 = animals1.get(0);

        // List<? super T>
        List<? super Dog> animals2 = new ArrayList<Animal>();
        // 可以向列表中添加Dog及其子类对象
        animals2.add(new Dog());
        animals2.add(new Cat());
        
         Object object1 =  animals2.get(0);
         Animal animal3= (Animal)animal3;
         Object object2 =  animals2.get(1);
         Animal animal4= (Animal)animal4;  
    }
}

3. 总结

(1)List<? extends T>适用于读取数据,读取出来的数据全部用T类型接收。如果我们往此 list 中添加 T 类型不同的子类的话,各种子类无法相互转换,因此不能添加元素,但可接受初始赋值。

(2)List<? super T>适用于添加元素,只能添加 T 类型或其子类类型。因为这些类型都能转换为T的任意超类类型(向上转型),因此我们可以对此 list 添加元素。只能用 Object 类型来接收获取到的元素,但是这些元素原本的类型会丢失。

点击下载《Java中List<? extends T>与List<? super T>的区别(值得珍藏)》

  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤蓬&听雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值