java lt t gt 是什么意思_Java中<? extends T>和<? super T>的理解

? 通配符类型

- extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类;

super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object;

上界 extends T>不能往里存,只能往外取

比如,我们现在定义:List extends T>首先你很容易误解它为继承于T的所有类的集合,你可能认为,你定义的这个List可以用来put任何T的子类,那么我们看下面的代码:

import java.util.LinkedList;

import java.util.List;

public class test {

public static void main(String[] args) {

List extends Father> list = new LinkedList<>();

list.add(new Son());

}

}

class Human{

}

class Father extends Human{

}

class Son extends Father{

}

class LeiFeng extends Father {

}

list.add(new Son());这行会报错:The method put(Son) is undefined for the type List

List extends Father表示 “具有任何从Son继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List 赋值。

你也许试图这样做:

List extends Father> list = new LinkedList();

list.add(new Son());

即使你指明了为Son类型,也不能用add方法添加一个Son对象。

list中为什么不能加入Father类和Father类的子类呢,我们来分析下。

List extends Father>表示上限是Father,下面这样的赋值都是合法的

List extends Father> list1 = new ArrayList();

List extends Father> list2 = new ArrayList();

List extends Father> list3 = new ArrayList();

如果List extends Father>支持add方法的话:

list1可以add Father和所有Father的子类;

list2可以add Son和所有Son的子类;

list3可以add LeiFeng和所有LeiFeng的子类。

下面代码是编译不通过的:

list1.add(new Father());//error

list1.add(new Son());//error

原因是编译器只知道容器内是Father或者它的派生类,但具体是什么类型不知道。可能是Father?可能是Son?也可能是LeiFeng,XiaoMing?编译器在看到后面用Father赋值以后,集合里并没有限定参数类型是“Father“。而是标上一个占位符:CAP#1,来表示捕获一个Father或Father的子类,具体是什么类不知道,代号CAP#1。然后无论是想往里插入Son或者LeiFeng或者Father编译器都不知道能不能和这个CAP#1匹配,所以就都不允许。

所以通配符>和类型参数的区别就在于,对编译器来说所有的T都代表同一种类型。比如下面这个泛型方法里,三个T都指代同一个类型,要么都是String,要么都是Integer。

public List fill(T... t);

但通配符>没有这种约束,List>单纯的就表示:集合里放了一个东西,是什么我不知道。

所以这里的错误就在这里,List extends Father>里什么都放不进去。

List extends Father> list不能进行add,但是,这种形式还是很有用的,虽然不能使用add方法,但是可以在初始化的时候一个Season指定不同的类型。比如:

List extends Father> list1 = getFatherList();//getFatherList方法会返回一个Father的子类的list

另外,由于我们已经保证了List中保存的是Father类或者他的某一个子类,所以,可以用get方法直接获得值:

List extends Father> list1 = new ArrayList<>();

Father father = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。

Object object = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。

Human human = list1.get(0);//读取出来的东西只能存放在Father或它的基类里。

Son son = (Son)list1.get(0);

下界

//super只能添加Father和Father的子类,不能添加Father的父类,读取出来的东西只能存放在Object类里

List super Father> list = new ArrayList<>();

list.add(new Father());

list.add(new Human());//compile error

list.add(new Son());

Father person1 = list.get(0);//compile error

Son son = list.get(0);//compile error

Object object1 = list.get(0);

因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制。既然元素是Father的基类,那往里存粒度比Father小的都可以。出于对类型安全的考虑,我们可以加入Father对象或者其任何子类(如Son)对象,但由于编译器并不知道List的内容究竟是Father的哪个超类,因此不允许加入特定的任何超类(如Human)。而当我们读取的时候,编译器在不知道是什么类型的情况下只能返回Object对象,因为Object是任何Java类的最终祖先类。但这样的话,元素的类型信息就全部丢失了。

PECS原则

最后看一下什么是PECS(Producer Extends Consumer Super)原则,已经很好理解了:

频繁往外读取内容的,适合用上界Extends。

经常往里插入的,适合用下界Super。

总结

extends 可用于返回类型限定,不能用于参数类型限定(换句话说:? extends xxx 只能用于方法返回类型限定,jdk能够确定此类的最小继承边界为xxx,只要是这个类的父类都能接收,但是传入参数无法确定具体类型,只能接受null的传入)。

super 可用于参数类型限定,不能用于返回类型限定(换句话说:? supper xxx 只能用于方法传参,因为jdk能够确定传入为xxx的子类,返回只能用Object类接收)。

? 既不能用于方法参数传入,也不能用于方法返回。

带有super超类型限定的通配符可以向泛型对象中写入,带有extends子类型限定的通配符可以向泛型对象读取。

在引用提到的"光看上面的定义除了摸不着头脑,不会有其它感觉"是指阅读代码时可能会感到困惑、难以理解,需要通过实际的代码运行环境来进行说明和解释。 而引用提到的"Eclipse 说: The interface Comparable cannot be implemented more than once with different arguments: Comparable&lt;Animal&gt; and Comparable&lt;Dog&gt;"是指在使用Eclipse编程环境时出现了错误,该错误提示表明接口Comparable不能被不同参数多次实现,对于Animal和Dog而言,他们应该选择一种实现方式。 此外,引用提到了"&lt;&gt;和" "表示编译器在搜索头文件时的顺序不同,&lt;&gt;表示从系统目录下开始搜索,然后再搜索PATH环境变量所列出的目录,不搜索当前目录,""是表示从当前目录开始搜索,然后是系统目录和PATH环境变量所列出的目录。所以,系统头文件一般用&lt;&gt;,用户自己定义的则可以使用"",加快搜索速度。"这是在讨论C++编程语言#include语句尖括号和双引号的区别,尖括号表示编译器从系统目录开始搜索头文件,双引号表示从当前目录开始搜索头文件。 因此,&gt;&gt;&gt;和In环境没有直接的联系。&gt;&gt;&gt;是Python解释器提示用户输入代码的符号,而In是指在Jupyter Notebook输入的代码块编号。这两者是不同的编程环境用于输入代码的标识符。&lt;span class="em"&gt;1&lt;/span&gt;&lt;span class="em"&gt;2&lt;/span&gt;&lt;span class="em"&gt;3&lt;/span&gt; #### 引用[.reference_title] - *1* *2* [&lt;T extends Comparable&lt;? super T&gt;&gt;泛型类型与&lt;T extends Comparable&lt;T&gt;&gt;的区别以及优越性](https://blog.csdn.net/qq_35580883/article/details/78627756)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [C++ #include<>和#include“ “的区别](https://blog.csdn.net/qq_36686437/article/details/121594064)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值