You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Predicate<? extends Number>编译报错?Collection泛型却正常

问题解析

核心原因:Predicate的参数消费特性与通配符误用

你对Collection<? extends Number>的理解是准确的:它表示集合中的元素是Number或其子类,遍历用Number接收是安全的——任何子类都可以向上转型为父类Number。

但Predicate<? extends Number>的逻辑完全不同:

  • Predicate<T>的test(T t)方法要求传入参数为T类型。当你声明Predicate<? extends Number>时,这个通配符意味着该Predicate可能是Predicate<Integer>、Predicate<Double>或Predicate<Number>中的任意一种。
  • 假设实际传入的是Predicate<Integer>,它的test方法仅接受Integer类型参数,但你传入的i是Number类型——Number是Integer的父类,无法安全向下转型为Integer,编译器无法保证类型安全,因此直接报错。

简言之:Collection<? extends Number>是产出元素的场景,协变通配符? extends适配这种场景;而Predicate是消费参数的场景,消费场景需要用逆变通配符? super。

修正方案

将Predicate的参数类型改为Predicate<? super Number>,确保test方法能接受Number及其所有子类的参数:

public int countSpecial(Collection<? extends Number> input, Predicate<? super Number> p) {
    int count = 0;
    for (Number i : input) {
        if (p.test(i)) {
            count++;
        }
    }
    return count;
}

另外,方法上的泛型声明<T extends Collection<? extends Number>>是多余的(方法内未使用T类型),直接删除即可。

补充:PECS原则

这个问题本质对应Java泛型的PECS原则:

  • Producer Extends:若对象是生产者(产出元素,如Collection遍历),使用? extends;
  • Consumer Super:若对象是消费者(接收元素,如Predicate的test方法),使用? super。

内容的提问来源于stack exchange,提问作者Ankit Ghildiyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 04:54:57