在看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的程序员们决定给泛型提供superextends两个通配符关键字来人为声明泛型参数类的继承关系。注意使用时一同添加的?的含义,虽然表示任意,但是不是任意类型,而是任意确定类型。好比摸奖的时候,手到箱子里抓了一个球,你没有办法口胡说摸了特等奖,摸了是啥就是啥,因为只要手从箱子里出来之后,是什么球大家都知道得清清楚楚。

但是显然非一一对应的映射是没有反函数的,因而就会出现这么一个问题:泛型类操作时的参数类型究竟是什么?显然如果这个问题不明确的话只有两种可能:编译器找不到合适的方法操作数据,罢工;编译器随性选了一种不合适的方法操作数据,搞砸。

所以这个时候就要通过使用的通配符,以及面向对象设计的基本原理来解决这个问题了。接下来用?代指使用泛型通配符时传入的具体类别,则对于<? extends Parent>,根据面向对象的特性有:

  1. ?类为任意固定的Parent类或其子类;
  2. ?类一定可以转换为Parent类(及其父类)的合法对象。

则根据第一条,可以发现,由于在Java中没有提供明确?类型的方法,出于安全考虑,实际上是不允许向<? extends Parent>类型的形参传入任何值的。相反,具有<? extends Parent>类型返回值的方法返回的都是Parent类型的对象。

因而,相当于使用了extends通配符的泛型类对象的所有泛型输入方法全部失效,泛型输出方法正常工作,但返回的是被extends的类对象。

那我要传入对象怎么办?

答案是反过来,使用super。而super又与extends恰好相反。在<? super Child>泛型类中:

  1. 任意固定的Child类或其父类为?类;
  2. Child类(及其子类)一定可以转化为?类的合法对象。

这也造成了与上面恰好相反的效果:使用了super通配符的泛型类对象的所有泛型输出方法全部失效,泛型输入方法正常工作,允许传入被super的类或其子类对象。

目前个人感觉super是为了弥补extends的缺陷,而不是作为设计的新功能而出现的。

红 蓝 黑 灰(我全都要)?

那还是回归最本源的面向对象吧,使用Object作为最稳固的桥梁将数据传递到位后,然后再做类型转换吧。当然,这种工作应该在保证方法安全性的前提下进行,比如List类型的indexOfcontains方法。

有时间了再来具体水水。现在对泛型理解还不够深,先码一下

标签: none

添加新评论