JAVA中的泛型与PECS 原则

PECS 原则

在使用限定通配符(bounded wildcard)时,需要遵守 PECS 原则。PECS 是 Producer-Extends, Consumer-Super 的缩写,是一种设计原则,用于指导使用泛型类型和限定通配符时的编程风格。

PECS 原则的核心思想是:Producer 使用 extends 通配符,Consumer 使用 super 通配符。

当泛型类型只用于产生(读取)元素时,即作为生产者时,使用 ? extends T 形式的限定通配符。这表示可以接受 T 或 T 的子类型。通过使用 extends,我们可以从集合中安全地获取元素,因为我们只关心元素的上界,而不关心具体的子类型。

当泛型类型只用于消费(写入)元素时,即作为消费者时,使用 ? super T 形式的限定通配符。这表示可以接受 T 或 T 的超类型。通过使用 super,我们可以向集合中安全地添加元素,因为元素一定是 T 或 T 的父类型。

通过遵循 PECS 原则,可以确保泛型在多态的使用中具有更灵活和安全的行为。下面是一些示例:

作为生产者使用 ? extends T:

public void process(List<? extends Animal> animals) {
    for (Animal animal : animals) {
        animal.eat();
    }
}

在上述例子中,List<? extends Animal> 可以接受 Animal 或 Animal 的子类型的集合。我们只关心元素是 Animal 或其子类型,因此可以安全地读取元素。

c作为消费者使用 ? super T:

public void feed(List<? super Dog> dogs) {
    dogs.add(new Dog());
    dogs.add(new Puppy());
}

在上述例子中,List<? super Dog> 可以接受 Dog 或 Dog 的父类型的集合。我们可以添加 Dog 或其子类型的实例到集合中,因为集合的元素至少是 Dog。但如果使用 List<? extends Dog>,则无法添加元素,因为无法确定元素的类型。

通过遵循 PECS 原则,可以确保代码更加灵活、类型安全,并且在处理泛型集合时提供更好的扩展性和适应性。

T extends Animal 和 ? extends Animal 之间的差别

T extends Animal 是一个泛型声明,它将类型参数 T 限定为 Animal 或 Animal 的子类型。这意味着我们在使用这个泛型类型时,可以指定具体的类型参数,例如 List< Dog >、List< Cat >

而 ? extends Animal 是一个通配符表达式,用于限定通配符类型。它表示可以接受任何 Animal 或 Animal 的子类型的实例。通配符类型一般用于方法的参数或返回类型中,以表示方法对具体类型的灵活性。

在使用上,T extends Animal 允许在编译时具体指定类型参数,而 ? extends Animal 只能接受一种未知类型的 Animal 或 Animal 的子类型。这意味着 ? extends Animal 可能更加灵活,因为它可以接受更多可能的类型参数。

下面是一些具体的示例,来说明两者之间的差别:

// 泛型声明
class SomeClass<T extends Animal> {
    // 使用具体的类型参数
    private List<T> animals;

    public SomeClass() {
        animals = new ArrayList<>();
    }

    public void addAnimal(T animal) {
        animals.add(animal);
    }

    public T getAnimal(int index) {
        return animals.get(index);
    }
}

// 通配符
void processAnimals(List<? extends Animal> animals) {
    for (Animal animal : animals) {
        animal.eat();
    }
}

public static void main(String[] args) {
    // 使用泛型声明
    SomeClass<Dog> dogClass = new SomeClass<>();
    dogClass.addAnimal(new Dog());
    dogClass.addAnimal(new Puppy()); // 是 Dog 的子类型,可以用于 T extends Animal

    Dog dog = dogClass.getAnimal(0);

    // 使用通配符类型
    List<Dog> dogs = new ArrayList<>();
    dogs.add(new Dog());
    dogs.add(new Puppy());

    processAnimals(dogs); // 可以匹配 ? extends Animal
}

总结来说,T extends Animal 是一种具体的类型参数限定,而 ? extends Animal 是一种灵活的通配符类型限定。根据具体需求,你可以选择使用其中之一来实现不同的泛型行为。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值