MST

星途 面试题库

面试题:Java泛型通配符的高级应用及原理

假设有两个类`Animal`及其子类`Dog`,定义一个`List<Dog>`。现在要编写一个方法,既能接收`List<Dog>`,也能接收`List<Animal>`,同时要保证类型安全。请详细说明如何使用泛型通配符实现,并解释`<? extends T>`和`<? super T>`的原理及区别。
33.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 使用泛型通配符实现方法

    import java.util.List;
    
    class Animal {}
    class Dog extends Animal {}
    
    public class Main {
        public static void processList(List<? extends Animal> list) {
            // 这里可以读取list中的元素,但不能添加新元素(除了null)
            for (Animal animal : list) {
                System.out.println(animal);
            }
        }
    }
    

    在上述代码中,processList方法的参数类型是List<? extends Animal>,这样它既可以接收List<Dog>(因为DogAnimal的子类),也可以接收List<Animal>,同时保证了类型安全。

  2. <? extends T>原理及说明

    • 原理<? extends T>表示类型的上界,即通配符代表的类型是T的子类(包括T本身)。
    • 读取和写入
      • 读取:可以从集合中读取元素,因为不管具体是T的哪个子类,都可以赋值给T类型的变量。例如上述代码中,从List<? extends Animal>中读取元素赋值给Animal类型变量是安全的。
      • 写入:不能向集合中写入除null以外的元素。因为编译器只知道集合中的元素是T的子类,但具体是哪个子类并不明确。如果写入一个具体的T的子类对象,可能与集合实际存储的子类类型不匹配。例如,假设集合实际是List<Dog>,如果向List<? extends Animal>写入一个CatCat也是Animal的子类)对象,就会出现类型错误。
  3. <? super T>原理及说明

    • 原理<? super T>表示类型的下界,即通配符代表的类型是T的超类(包括T本身)。
    • 读取和写入
      • 读取:从集合中读取元素时,由于不知道具体的超类类型,所以只能将读取的元素赋值给Object类型(因为Object是所有类的超类)。例如List<? super Dog>,读取元素时只能用Object类型接收。
      • 写入:可以向集合中写入T类型或T的子类类型的元素。因为T及其子类对象肯定可以赋值给T的超类类型的变量。例如对于List<? super Dog>,可以向其中写入Dog对象或者Dog的子类对象(如Poodle,假设PoodleDog的子类)。
  4. 区别总结

    • <? extends T>:侧重于读操作,保证从集合中读取的元素可以安全地赋值给T类型变量,但限制了写操作。
    • <? super T>:侧重于写操作,保证可以安全地向集合中写入T及其子类对象,但读操作受限,只能用Object类型接收读取的元素。