Java泛型的应用

本文深入探讨了Java泛型中的<TextendsComparable<?superT>>的含义及应用场景,通过对比<TextendsComparable<T>>解释了这种泛型用法的优势,并附带实例代码加以说明。

在观察Java源码的时候,发现了这么一个写法T extends Comparable<? super T>。不禁纳闷为什么要这么写呢?有什么好处吗,extends和super在这里的作用着实让人有点不清楚。

 

接下来,我将结合代码跟大家分享一下我关于这里泛型应用的看法。

 

<T extends Comparable<? super T>>

代表什么意思?

 

大家可以明白的是这里应用到了Java的泛型,那么首先向大家说明一下这里extends的作用。

 

extends后面跟的类型,如<任意字符 extends 类/接口>表示泛型的上限。示例代码如下:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

在理解了extends所表示的泛型的上限后,接下来介绍一下super的作用,它与extends相反,表示的是泛型的下限。

 

所以结合上述两点,我们来分析一下这句话整体代表什么意思。首先,extends对泛型上限进行了限制即T必须是Comparable<? super T>的子类,然后<? super T>表示Comparable<>中的类型下限为T!

 

<T extends Comparable<T>> 和 

<T extends Comparable<? super T>>

 有什么不同?

 

接下来我们通过对比,使得大家对为何要这样编写代码有更加深刻的印象。

 

<T extends Comparable<T>>

 

它代表的意思是:类型T必须实现Comparable接口,并且这个接口的类型是T。这样,T的实例之间才能相互比较大小。这边我们以Java中GregorianCalendar这个类为例。

 

代码如下所示:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

这里编译报错,因为这里的<T extends Comparable<T>>相当于<GregorianCalendar extends Comparable<GregorianCalendar>>,但是GregorianCalendar中并没有实现Comparable<GregorianCalendar>,而是仅仅持有从Calendar继承过来的Comparable<Calendar>,这样就会因为不在限制范围内而报错。

 

<T extends Comparable<? super T>>

 

它代表的意思是:类型T必须实现Comparable接口,并且这个接口的类型是T或者是T的任一父类。这样声明后,T的实例之间和T的父类的实例之间可以相互比较大小。同样还是以GregorianCalendar为例。代码如下所示:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

此时编译通过,这里可以理解为

<GregorianCalendar extend

s Comparable<Calendar>>!因为Calendar为

GregorianCalendar 的父类并且

GregorianCalendar 实现了

Comparable<Calendar>,具体可以在API中进行查看!

 

实例代码演示

 

代码如下所示:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

上面的代码包括三个类:

 

1、Animal实现了Comparable<Animal>接口,通过年龄来比较实例的大小;

 

2、 Dog从Animal继承,为其子类;

 

3、Test类中提供了两个排序方法和测试用的main()方法:

 

  • mySort1()使用<T extends Comparable<T>>类型参数;

  • mySort2()使用<T extends Comparable<? super T>>类型参数;

  • main()测试方法。在这里将分别创建Animal和Dog两个序列,然后调用排序方法对其进行测试。

 

对mySort1()进行测试,

main方法代码如下所示

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

结果编译出错,报错信息为:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

mySort1() 方法的类型参数是<T extends Comparable<T>>,它要求的类型参数是类型为T的Comparable。

 

如果传入的是List<Animal>程序将正常执行,因为Animal实现了接口Comparable<Animal>。

 

但是,如果传入的参数是List<Dog>程序将报错,因为Dog类中没有实现接口Comparable<Dog>,它只从Animal继承了一个Comparable<Animal>接口。

 

注意:animals list中实际上是包含一个Dog实例的。如果碰上类似的情况(子类list不能传入到一个方法中),可以考虑把子类实例放到一个父类 list 中,避免编译错误。

 

对mySort12()进行测试,

main方法代码如下所示:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

这时候我们发现该程序可以正常运行。它不但能够接受Animal implements

 Comparable<Animal>这样的参数,也可以接收:Dog implements Comparable<Animal>这样的参数。

 

是否可以通过将Dog实现

Comparable<Dog>来解决问题?

 

由分析可得程序出现问题是因为Dog类没有实现接口Comparable<Dog>,那么我们能否将该类实现接口Comparable<Dog>来解决问题呢?

 

代码如下所示:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

结果程序编译报错,错误信息如下所示:

 

640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1

 

意义是Dog类已经从Animal中继承了Comparable该接口,无法再实现一个Comparable。

 

若子类需要使用自己的比较方法,则需要重写父类的public int CompareTo(Animal other)方法。

 

总结

 

对Animal/Dog这两个有父子关系的类来说:<T extends Comparable<? super T>>可以接受List<Animal>,也可以接收 List<Dog> 。而<T extends Comparable<T>>只可以接收 List<Animal>所以,<T extends Comparable<? super T>>这样的类型参数对所传入的参数限制更少,提高了 API 的灵活性。总的来说,在保证类型安全的前提下,要使用限制最少的类型参数。

转载于:https://my.oschina.net/zjg23/blog/1492483

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值