Java中 <? super T>,<? extends T>,和<T>的区别

本文详细解析Java泛型的使用,通过测试代码展示<?superT>和<?extendsT>的区别,并分析不同场景下的类型约束。
在看Collections源代码中,看到如下代码:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
    Object[] a = list.toArray();
    Arrays.sort(a);
    ListIterator<T> i = list.listIterator();
    for (int j=0; j<a.length; j++) {
        i.next();
        i.set((T)a[j]);
    }
}

有点郁闷,不知道一下代码是啥意思
<T extends Comparable<? super T>>

百度后了解了这是Java泛型的知识点,然后就自己测试一下,以下是测试代码:
/**
 * Created by CSH on 12/7/2015.
 */
//测试泛型
public class TestGeneric {

    @Test
    public void test01(){
        new A<If<Father>>();    //不报错
        new B<If<Father>>();    //不报错
        new C<If<Father>>();    //不报错

        new A<If<Child>>();     //报错
        new B<If<Child>>();     //报错
        new C<If<Child>>();     //不报错

        new A<If<GrandFather>>();   //不报错
        new B<If<GrandFather>>();   //报错
        new C<If<GrandFather>>();   //报错
    }

}
class GrandFather {

}
class Father extends GrandFather{

}
class Child extends Father {

}

interface If<T>{
    void doSomething();
}

class A  <T extends If<? super Father>> {
}

class B <T extends If<Father>> {
}

class C <T extends If<? extends Father>>{
}

结果是:
这例子可以区分super和extends这2个关键字的区别
super:<? super Father> 指的是Father是上限,传进来的对象必须是Father,或者是Father的父类,因此 new A<If<Child>>()会报错,因为Child是Father的子类
extends:<? extends Father> 指的是Father是下限,传进来的对象必须是Father,或者是Father的子类,因此 new C<If<GrandFather>>()会报错,因为GrandFather是Father的父类
<Father> 指的是只能是Father,所以new B<If<Child>>()和 new B<If<GrandFather>>()都报错

知乎上的网友解释链接:点击打开链接
 
 

                
<think>好的,我需要回答用户关于Java中<? extends T><? super T>的基本用法的问题。首先,我得回忆一下相关的知识,确保自己理解正确。根据用户提供的引用内容,特别是引用[3][4],这两个通配符分别代表上界下界通配符。 用户可能需要一个简明扼要的解释,所以应该先分别说明两种通配符的作用。比如,<? extends T>用于读取数据,而<? super T>用于写入数据。然后,用实际的例子来说明,这样用户更容易理解。 接下来,我需要考虑如何组织内容。可能的结构是:先介绍每个通配符的定义用途,然后给出使用场景示例代码。比如,<? extends T>适用于需要从集合中获取元素的情况,而<? super T>适用于向集合中添加元素的情况。同时,要注意类安全的问题,比如在extends的情况下不能添加元素,而在super的情况下获取元素类受限。 还要记得引用用户提供的参考资料,比如在解释上界下界时引用[3][4]。可能还需要提到PECS原则(Producer Extends, Consumer Super),这样用户能更好地记忆应用场景。 然后,检查是否有遗漏点,比如类擦除的影响,但用户的问题是关于基本用法,可能不需要深入到这里。不过,确保提到类安全的关键点,比如为什么在使用extends时不能添加元素,编译器如何限制这些操作。 最后,生成相关问题,帮助用户进一步学习。例如,询问区别、应用场景或PECS原则的相关问题。确保问题与回答内容相关,并且引导用户深入理解。</think>### Java中<? extends T><? super T>的基本用法 #### 1. **<? extends T>(上界通配符)** - **定义**:表示接受`T`或其子类,强调“生产者”(Producer)角色,即从容器中读取数据[^3][^4]。 - **使用场景**: - 需要从集合中安全地读取元素,且不关心具体子类。 - **不能添加元素**(除`null`外),因为编译器无法确定具体子类。 - **示例**: ```java // 读取Number及其子类(如Integer)的集合 void printNumbers(List<? extends Number> list) { for (Number num : list) { System.out.println(num); } } // 调用:可以传入List<Integer>或List<Double> List<Integer> integers = Arrays.asList(1, 2, 3); printNumbers(integers); // 合法 ``` #### 2. **<? super T>(下界通配符)** - **定义**:表示接受`T`或其父类,强调“消费者”(Consumer)角色,即向容器写入数据[^3][^4]。 - **使用场景**: - 需要向集合中添加`T`或其子类的元素。 - **读取时类受限**,只能以`Object`类接收。 - **示例**: ```java // 向集合中添加Integer或其子类(如Long) void addIntegers(List<? super Integer> list) { list.add(10); list.add(20L); // 编译错误!Long是Integer的父类吗? } // 调用:可以传入List<Number>或List<Object> List<Number> numbers = new ArrayList<>(); addIntegers(numbers); // 合法 ``` #### 3. **PECS原则(Producer-Extends, Consumer-Super)** - **核心规则**:根据容器是“生产者”还是“消费者”选择通配符[^4]。 - **Producer**(提供数据):使用`<? extends T>`。 - **Consumer**(消费数据):使用`<? super T>`。 - **示例对比**: ```java // 生产者:从src读取数据 public static <T> void copy(List<? extends T> src, List<? super T> dest) { for (T item : src) { dest.add(item); } } // 调用:src可以是List<String>,dest可以是List<Object> List<String> src = Arrays.asList("A", "B"); List<Object> dest = new ArrayList<>(); copy(src, dest); // 合法 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值