Java基础之【泛型的T和?区别】

博客介绍了泛型中<T>和<?>的使用区别。<T>用于泛型类型声明,可进行get和set操作;<?>用于方法接收参数或返回类型,只能get不能set(set null无意义),原因是<?>未知类型,而get访问都是Object类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<T>用于泛型类型的声明上 可以get set

<?>用于方法的接收参数或者是返回类型 只能get(不能set 其实可以set null但是无意义),思考:因为<?>不知道是什么类型 所以无法set,但是get即访问是可以的,因为都是Object

<think>嗯,用户现在问的是Java的上限下限,也就是的通配符中的extendssuper。之前用户问过printf的格式化输出,现在转向了基础知识。可能用户正在学习Java基础,特别是这一块,想深入理解类参数的限制。 首先,我需要确定用户已经了解的基本概念,比如什么是类、方法,以及为什么需要。可能用户已经知道用于类安全,避免强制类转换,但上限下限可能对他们来说有点抽象。需要从基础讲起,但也要深入例子,帮助理解。 接下来,用户可能对上下限的应用场景不太清楚,比如什么时候用extends,什么时候用super。这时候需要举一些实际的例子,比如在集合类中的应用,比如List<? extends Number>List<? super Integer>的区别。同时,PECS原则(Producer Extends, Consumer Super)可能需要解释清楚,这样用户能理解在方法参数中如何选择。 另外,用户可能会混淆类参数的上限通配符的上限。比如,在定义类时,<T extends Number>方法的参数List<? extends Number>是不同的。需要指出这两者的区别,避免混淆。 可能用户在实际编程中遇到了需要限制的情况,比如写一个方法,只能处理数字类的列表,或者需要向列表中添加元素。这时候上限下限就显得很重要了。通过实际的代码示例,比如遍历一个extends的列表,或者向一个super的列表添加元素,能帮助用户更好地理解。 还要注意用户可能的误区,比如使用extends时不能添加元素,只能读取,而super可以添加特定类的元素。这些限制需要明确说明,避免用户在实际使用中出现错误。 另外,用户可能想知道上下限在类擦除后的影响,但这个问题比较复杂,可能暂时不需要深入,除非用户有更高级的问题。目前重点放在语法应用上。 最后,总结部分需要简明扼要,回顾上限下限的作用,以及它们的典应用场景,帮助用户巩固记忆。可能还需要提到常见的错误,比如错误地尝试添加元素到extends通配符的集合中,导致编译错误,提醒用户注意。 总之,回答需要结构清晰,从定义、语法、示例、应用场景到注意事项,逐步展开,确保用户能够逐步理解上下限的概念用法。同时,结合之前的printf问题,保持回答的一致性,使用用户已经适应的格式示例风格。</think>以下是关于Java**上限(Upper Bound)**与**下限(Lower Bound)**的详细解析: --- ### **一、核心概念** #### **1. 上限(`<? extends T>`)** - **作用**:限制的**最大范围**,表示必须是`T`或其**子类**。 - **本质**:定义类的**生产者(Producer)**,主要用于**安全读取数据**。 - **语法**:`Class<? extends T>` 或 `T<? extends U>` #### **2. 下限(`<? super T>`)** - **作用**:限制的**最小范围**,表示必须是`T`或其**父类**。 - **本质**:定义类的**消费者(Consumer)**,主要用于**安全写入数据**。 - **语法**:`Class<? super T>` 或 `T<? super U>` --- ### **二、代码示例与对比** #### **1. 上限(`extends`)** ```java // 定义方法:接收Number及其子类的列表(如Integer、Double) public static void printNumbers(List<? extends Number> list) { for (Number num : list) { // 安全读取 System.out.print(num + " "); } } // 调用 List<Integer> intList = Arrays.asList(1, 2, 3); List<Double> doubleList = Arrays.asList(1.1, 2.2); printNumbers(intList); // 合法 ✅ printNumbers(doubleList); // 合法 ✅ ``` **限制**: - **不可写入**:`list.add(10)` 会编译报错 ❌ - **原因**:Java无法确定实际类是否匹配(可能是`Integer`或`Double`) --- #### **2. 下限(`super`)** ```java // 定义方法:接收Integer及其父类的列表(如Number、Object) public static void addIntegers(List<? super Integer> list) { list.add(10); // 安全写入 ✅ list.add(20); } // 调用 List<Number> numList = new ArrayList<>(); List<Object> objList = new ArrayList<>(); addIntegers(numList); // 合法 ✅ addIntegers(objList); // 合法 ✅ ``` **限制**: - **读取不安全**:`Integer i = list.get(0)` 需强制类转换 ❌ - **原因**:实际类可能是`Number`或`Object` --- ### **三、核心规则(PECS原则)** | **场景** | **选择** | **记忆口诀** | |-----------------------|------------------|---------------------------| | 需要**读取数据**(生产者) | `<? extends T>` | **Producer Extends** | | 需要**写入数据**(消费者) | `<? super T>` | **Consumer Super** | --- ### **四、应用场景** #### **1. 上限的典用途** - **集合的只读操作** ```java // 安全遍历任何Number子类的集合 public static double sum(List<? extends Number> list) { double total = 0; for (Number num : list) { total += num.doubleValue(); } return total; } ``` - **API设计中的类约束** ```java // 限制键类必须实现Comparable class SortedMap<K extends Comparable<? super K>, V> { ... } ``` --- #### **2. 下限的典用途** - **写入集合** ```java // 将多个Integer添加到父类集合 public static void fill(List<? super Integer> list, int count) { for (int i = 0; i < count; i++) { list.add(i); // 安全写入 } } ``` - **回调函数设计** ```java // 接收Consumer<? super T>,兼容父类处理器 public void process(List<T> data, Consumer<? super T> consumer) { data.forEach(consumer); } ``` --- ### **五、类参数与通配符的对比** | **特性** | **类参数(`<T>`)** | **通配符(`<?>`)** | |---------------------|--------------------------|----------------------------| | 定义位置 | 类/方法声明时 | 方法参数或变量类 | | 可操作性 | 可直接使用类`T` | 需配合`extends`/`super` | | 典用途 | 定义类或方法 | 灵活约束已有 | | 示例 | `class Box<T> { ... }` | `void print(List<?> list)` | --- ### **六、常见误区与避坑指南** 1. **混淆`extends`与`super`** - 错误:尝试向`List<? extends Number>`添加`Double` - 正确:改用`List<? super Double>` 2. **过度使用通配符** - 错误:`Map<?, ?> map = new HashMap<>();` - 正确:明确具体类参数(除非确实需要完全未知类) 3. **忽略PECS原则** - 错误:在需要写入数据的方法中使用`<? extends T>` - 正确:根据操作方向选择通配符类 --- ### **七、底层原理** - **类擦除**:信息在编译后被擦除,转换为原始类(Raw Type) - **桥方法生成**:编译器自动生成方法保证类安全 - **通配符捕获**:通过辅助方法捕获具体类(如`helper(List<T> list)`) --- ### **总结** | **特性** | **上限(`<? extends T>`)** | **下限(`<? super T>`)** | |-----------------|------------------------------------|----------------------------------| | **方向** | 限制类为`T`的子类 | 限制类为`T`的父类 | | **操作权限** | 只读(安全读取) | 可写(安全写入) | | **典场景** | 数据生产者(如遍历集合) | 数据消费者(如填充集合) | 掌握上下限是写出**类安全**且**灵活**的Java代码的关键,尤其在集合操作API设计中应用广
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值