1:为什么说T是代表特定类型,?代表任意类型,T不也是未知任意的类型吗,具体的要由实例化时传入的类型决定,传入之前不也是未知任意的吗?
2:下图如何理解?
为什么说?的意义是实例化泛型参数,?不是代表任意类型吗(如果去掉图中的extends),怎么能实例化类型参数T呢,他自己本身就是任意类型?
针对两个疑问单独回答一下我自己的理解吧
第一问:
感觉题主是太只看定义,不把定义放在定义需要的环境中看,我可以举个通俗的例子,比如我们时常在武打小说或者剧本里看到的描述
小明一拳打到小刚身上,小刚后撤一步,突然,小李及时赶到,使出一招动感光波打的小明前仰后翻
假如这个小说被拍成电视剧,那小明这个角色,任何一个演员都可以演,但是只要他演,他就只能做出一个动作,就是一拳打小刚,后面再前仰后翻,他不能后撤一步,他也不能发动感光波,这就是特定的类型,他只能出现在特定的场景中,而且必须符合
此时我们再把小说改改
小明一拳打到那个谁身上,那个谁后撤一步,突然,小李及时赶到,使出一招动感光波打的小明前仰后翻
此时小明一拳打到了那个谁,那这个那个谁的角色谁来演,那也是任意都可以的,就算开始演员1演,后面还可以改成演员2演,不重要,因为剧本里对于这个角色没有限定,其实就是群演,这就是任意类型
无论那个谁,还是小明,小刚,小李,其实只是剧本里的限定词,是角色,帮助理解剧情的
所以把T
和?
放在java
代码里来看,代码就是剧本,那T
和?
其实也只是限定词,限定类型,保证编译安全,那在代码中出现T
的类型,那永远都是特定的某一类型,它是小明一样的存在,而?
却是没有任何限制,它是那个谁,是群演的存在,所以它们的特定和任意就是指这个意思
第二问:
可能是这些术语太拗口了吧,你可以不用管太多,因为T
和?
都只是限定词,就不要太在意他们具体怎么实例化了,就像你写剧本的还要关心这个角色由哪个演员来演么?你只要清楚剧本里有哪些角色就可以了,他们到底有什么复杂的爱恨情仇就行。
就算是<? extends E>
按照我们之前剧本的例子来讲,那就变成
小明一拳打到红发男身上,红发男后撤一步,突然,小李及时赶到,使出一招动感光波打的小明前仰后翻
这里的红发男就是对于任意演员的一个限制,必须要求是红发的,在代码里跟<? extends E>
效果就差不多了
泛型本质也只是为了保证代码编译时类型安全
这就相当于保证剧本的故事通畅,不能各个角色乱了套,不然故事没办法讲明白,代码同理
以上就是我的小小例子吧,不知道是否够通俗ヾ(′?`o)+ 不同俗我也没办法了
###可能看官方文档最直接。
我们用常规类型时不区分场景,但泛型要区分:是声明、还是调用,是类、还是方法,是形参、还是实参,是入参、还是出参。
声明时,可能有多个不同泛型,代替不同类型,此时就要区分,通常用T,N,E,K,V等字母表示。
最常用的类型参数名称为:
- E-元素(由Java Collections Framework广泛使用)
- K键
- N-数字
- T型
- V-值
- S,U,V等-第二,第三,第四类型
extends 用于声明有界类型,界可以是多个,声明方式如下:
<T extends B1 & B2 & B3>
如:
class A { /\* ... \*/ } // 原文Class 是大写,是错的。
interface B { /\* ... \*/ }
interface C { /\* ... \*/ }
class D <T extends A & B & C> { /\* ... \*/ }
需要注意的是:
给定两个具体类型A和B(例如Number和Integer),无论A和B是否相关,MyClass 与 MyClass 没有关系。MyClass 和MyClass 的公共父对象是Object。 有关在类型参数相关时如何在两个泛型类之间创建类似子类型的关系的信息,请参见 Wildcards和Subtyping。
在泛型代码中,?称为通配符,表示未知类型。通配符可以在多种情况下使用:作为参数,字段或局部变量的类型;有时作为返回类型(尽管更具体的指明是更好的编程习惯)。通配符从不用作泛型方法调用,泛型类实例创建或超类型的类型参数。
以下各节将更详细地讨论通配符,包括上限通配符,下限通配符和通配符捕获。
<?>
单个问号也称作无限通配符,对类型没有限制。
<? extends T>
被称作是上限通配符。使用上限通配符是为了放宽对变量的限制。
<? super A>
被称作下限通配符。
对于以下声明
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}
调用 addNumbers 时可以传入 List<Object>, List<Number>或 List<Integer>,因为这些类是 Integer 的超类。
这里,super 和 extends 使用的主要区别在于参数是用于入参还是出参(相当于 C 语言的函数参数的指针类型*和取地址类型&),参考 https://docs.oracle.com/javas...。
通配符准则:
- 使用extends关键字,使用上限通配符定义“in”变量。
- 使用super关键字使用下界通配符定义“out”变量。
- 如果可以使用Object类中定义的方法访问“in”变量,请使用无界通配符(即
?
)。 - 如果代码需要同时使用“in”和“out”变量来访问变量,则不要使用通配符。
想象一个具有两个参数的copy方法:copy(src,dest)。该src参数提供将要复制的数据,所以它是“in”参数。dest参数接受数据,因此它是“out”参数。
如果代码需要同时使用“in”和“out”变量来访问变量,相当于是 super 和 extends 的交集,那只能是一个特定的类型了,所以就不能用有界通配符了
为避免产生运行时开销,Java 编译器会通过插入类型转换和生成桥接方法等技术对类型进行擦除
类型擦除可确保不会为参数化类型创建新的类;因此,泛型不会产生运行时开销。
###?
相当于通配符,比如fun(List<?> p)
可以接收任意的List
类型的参数,fun(List<? extends Number> p)
只能接收Number
及其子类型。
对你有帮助的话请点个采纳点个赞,谢谢?
###没记错的话,如果某个变量是?泛型的,则这个变量只能读,不能修改。