Java中无法直接限制ArrayList只能存储特定父类,因其泛型参数在实例化时指定;应通过方法签名中的有界类型参数(如)或通配符上界(? extends Number)来约束可接受的实参类型。

Java 中不能直接用泛型边界“限制 ArrayList 本身只能存储特定父类”,因为 ArrayList 是一个具体类,它的泛型参数(如 ArrayList)是在**实例化时指定的类型**,而不是靠边界语法去“约束类定义”。真正起作用的是:在声明或方法参数中,用有界类型参数(extends 或 super)来限定**可接受的泛型实参范围**,从而控制能存什么、能取什么、能传给谁。
用上界(extends)限定方法参数,只接受某父类及其子类
这是最常见也最实用的方式。比如你想写一个处理所有数字类型列表的方法,只允许传入 ArrayList、ArrayList、ArrayList 等,但拒绝 ArrayList:
- 定义方法时用
声明类型参数 - 方法形参写成
ArrayList或更宽松的List - 这样调用时,编译器会检查实参是否满足
T是Number的子类(含Number自身)
示例:
public static <t extends number> double sum(List<t> numbers) {
return numbers.stream()
.mapToDouble(Number::doubleValue)
.sum();
}</t></t>
✅ 可以传:new ArrayList、new ArrayList、new ArrayList
❌ 不可传:new ArrayList、new ArrayList(编译报错)
用通配符上界(? extends)接收只读列表
如果方法只读不写(比如遍历、统计、转换),推荐用通配符 ? extends Parent,它比泛型方法更灵活:
-
List extends Number>表示“某个确定的 Number 子类型列表”,例如可能是List,也可能是List,但你不知道具体是哪个 - 可以安全地
get()出Number(因为所有元素都肯定是Number或其子类) - 但不能
add()任何值(除了null),因为编译器无法保证你加的对象符合那个“未知的具体子类型”
示例:
public static void printNumbers(List extends Number> list) {
for (Number n : list) { // ✅ 安全:n 至少是 Number
System.out.println(n);
}
// list.add(42); // ❌ 编译错误:无法确定该加什么类型
}
为什么不能直接“限制 ArrayList 类只存某父类”?
因为 ArrayList 是 JDK 提供的通用容器,设计目标就是支持任意引用类型。它的源码里是 class ArrayList,没有内置边界。你无法修改它来强制要求 E extends Number —— 那就不是标准 ArrayList 了。
- 若真需要强约束,可封装一层:定义自己的
NumberList extends ArrayList,但注意这仍允许存Number任意子类,且失去泛型灵活性 - 更合理做法是:把边界逻辑放在使用端(方法签名、变量声明),而非容器定义端
下界(? super)适合“只写”场景,不用于限制存储父类
? super Integer 表示“Integer 或其任意父类的列表”,如 List、List。它允许你往里 add(Integer),但取出时只能当 Object 处理。
- 这不是用来“限制 ArrayList 只存某父类”,而是为“向更宽类型的集合安全添加子类对象”服务
- 例如:把一批
Integer添加到List,用List super Integer>做参数即可
示例:
public static void addInts(List super Integer> list) {
list.add(100); // ✅ 允许:Integer 可以放进 Number/Object 列表
// Integer i = list.get(0); // ❌ 不行:取出的可能是 Object,无法保证是 Integer
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











