java中用? extends number编写数字累加器时,因上界通配符只支持安全读取而不允许写入,故适用于只读累加场景;其通过doublevalue()统一运算,兼顾精度与兼容性,且比泛型方法更灵活。

Java中用上界通配符 ? extends T 编写数字累加器时,**不能直接用于接收可变参数或修改集合**,因为 ? extends Number 表示“某个未知的 Number 子类型”,编译器禁止向其中添加任何元素(包括 null 以外的值)。但可以安全地从中读取数据——这正是累加器的核心需求:只读取、不写入。
理解上界通配符的适用场景
累加器需要处理 Integer、Double、Long 等各种数字类型,但它们没有共同的数值运算接口。Java 的 Number 是所有包装数字类的父类,而 ? extends Number 正好能表达“一个只读的、元素为某种具体数字子类型的集合”。关键点:
-
List extends Number>可以传入List<integer></integer>或List<double></double>,类型安全 - 只能调用返回
Number的方法(如get()),不能调用add()、set() - 累加时需通过
doubleValue()统一转为 double 运算(或根据精度需求选longValue())
编写泛型累加器工具类
以下是一个基于上界通配符的静态工具类,支持从任意 Number 子类型集合中累加:
public class NumberAccumulator {
// 接收 ? extends Number,保证输入安全且通用
public static double sum(List extends Number> numbers) {
if (numbers == null) return 0.0;
double total = 0.0;
for (Number num : numbers) {
if (num != null) {
total += num.doubleValue(); // 统一转 double,兼顾精度与兼容性
}
}
return total;
}
// 支持数组(需用 Number[],不能用 ? extends Number[] —— 数组不支持通配符)
public static double sum(Number[] numbers) {
if (numbers == null) return 0.0;
double total = 0.0;
for (Number num : numbers) {
if (num != null) {
total += num.doubleValue();
}
}
return total;
}
}
使用示例:
List<integer> ints = Arrays.asList(1, 2, 3); List<double> doubles = Arrays.asList(1.5, 2.5, 3.0); System.out.println(NumberAccumulator.sum(ints)); // 6.0 System.out.println(NumberAccumulator.sum(doubles)); // 7.0</double></integer>
为什么不用 ?
如果定义为 <t extends number> double sum(List<t> list)</t></t>,看似更“泛型”,但实际会限制调用:
✅ sum(List<integer>)</integer> 可以
❌ sum(List<number>)</number> 也可以(T=Number)
⚠️ 但 sum(List extends Number>) 更灵活——它允许传入任意具体子类型列表,而泛型方法在类型推断时可能失败(例如 List 被声明为 List extends Number> 时无法直接传给 <t> sum(List<t>)</t></t>)。
上界通配符在此场景下更符合“消费”语义(Consumer),是更自然的选择。
注意事项与替代方案
上界通配符适合只读场景,但若需更高精度(如避免 double 丢失 long 精度),可提供重载:
- 增加
long sumLong(List extends Number>),内部用longValue(),但需注意溢出 - 对 BigDecimal 数据,单独提供
BigDecimal sumDecimal(List<bigdecimal>)</bigdecimal>,不混用通配符(因 BigDecimal 不继承自 Number 的算术逻辑) - Java 8+ 可结合 Stream:
numbers.stream().mapToDouble(Number::doubleValue).sum(),语义清晰且简洁
不复杂但容易忽略:通配符不是万能的,它解决的是**类型安全的只读泛化**,而不是替代泛型方法的设计意图。用对地方,才真正发挥其价值。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











