Java泛型通配符
在看Spring WebFlux的时候,看到了这么一段代码:
public interface Publisher<T>
{
public void subscribe(Subscriber<? super T> s);
}
之前在写Java程序的时候,看到部分Java内置类型中就出现过类似的表达,即<? super T>
。当时也没考虑过这玩意具体有什么用,如果仅仅只是看表达式的话,很容易理解它要表达的基础意思:这里要传入一个类,要求该类是T的父类。但是有什么用呢?怕你传入一个T的子类?虽然这么说听起来的确有点道理,但显然这个设计要表达的不是这个意思。
基础介绍可以参见这两篇还行的文章: https://blog.csdn.net/qq_29951485/article/details/88068338 https://www.cnblogs.com/hoojjack/p/6817547.html?utm_source=itdadao&utm_medium=referral
总而言之目的是提供泛型类之间的继承关系。很容易从文章中看出的是,编译器不会认泛型参数之间的继承关系,因而Sun的程序员们决定给泛型提供super
和extends
两个通配符关键字来人为声明泛型参数类的继承关系。注意使用时一同添加的?
的含义,虽然表示任意,但是不是任意类型,而是任意确定类型。好比摸奖的时候,手到箱子里抓了一个球,你没有办法口胡说摸了特等奖,摸了是啥就是啥,因为只要手从箱子里出来之后,是什么球大家都知道得清清楚楚。
但是显然非一一对应的映射是没有反函数的,因而就会出现这么一个问题:泛型类操作时的参数类型究竟是什么?显然如果这个问题不明确的话只有两种可能:编译器找不到合适的方法操作数据,罢工;编译器随性选了一种不合适的方法操作数据,搞砸。
所以这个时候就要通过使用的通配符,以及面向对象设计的基本原理来解决这个问题了。接下来用?
代指使用泛型通配符时传入的具体类别,则对于<? extends Parent>
,根据面向对象的特性有:
?
类为任意固定的Parent
类或其子类;?
类一定可以转换为Parent
类(及其父类)的合法对象。
则根据第一条,可以发现,由于在Java中没有提供明确?
类型的方法,出于安全考虑,实际上是不允许向<? extends Parent>
类型的形参传入任何值的。相反,具有<? extends Parent>
类型返回值的方法返回的都是Parent
类型的对象。
因而,相当于使用了extends
通配符的泛型类对象的所有泛型输入方法全部失效,泛型输出方法正常工作,但返回的是被extends
的类对象。
那我要传入对象怎么办?
答案是反过来,使用super
。而super
又与extends
恰好相反。在<? super Child>
泛型类中:
- 任意固定的
Child
类或其父类为?
类; Child
类(及其子类)一定可以转化为?
类的合法对象。
这也造成了与上面恰好相反的效果:使用了super
通配符的泛型类对象的所有泛型输出方法全部失效,泛型输入方法正常工作,允许传入被super
的类或其子类对象。
目前个人感觉super
是为了弥补extends
的缺陷,而不是作为设计的新功能而出现的。
红 蓝 黑 灰(我全都要)?
那还是回归最本源的面向对象吧,使用Object作为最稳固的桥梁将数据传递到位后,然后再做类型转换吧。当然,这种工作应该在保证方法安全性的前提下进行,比如List
类型的indexOf
和contains
方法。
有时间了再来具体水水。现在对泛型理解还不够深,先码一下