Java comparable接口及compareTo返回值所决定的升序降序问题
我们在学习java基础的时候知道,基本数据类型数组可以直接调动Arrays类的静态sort方法,然后输出。
例如: int iArr[] = {1,2,4,6}; Arrays.sort(iArr); 然后利用for循环输出..
但是如果我们是对象数组的话,则对象所在的类必须实现comparable接口,覆写它的compareTo方法,并且要有不同的返回值,代表升序和降序。
但是会有一个疑问:为什么对象数组调用Arrays.sort 必须要实现comparable接口呢?而且compareTo的返回值到底代表什么意义呢,它又是如何决定数组的升序和降序的呢?
带着这样的疑问,我自己写了一个很简单的例子,然后进行调试,跟进源码,终于发现的一点端倪,然后把我自己理解分享给大家
关于如何进入源码,以及查看源码中与变量有关的信息我的有一篇博客讲到 补充 ,有时间可以去看下。。
接下来上代码://Test类 package TEST;
接下来我们加入断点进行调试
首先我们进入方法1: Arrays.class中的sort()方法
接下来进入方法2:ComparableTimSort.class 的sort()方法
下一步进入:方法3:ComparableTimSort.class的countRunAndMakeAscending方法里面终于见到了我们的CompareTo方法
这里你应该终于明白了为什么一定要实现comparable接口中的compareTo方法了吧。
如何你没有实现,那么通过接口去找compareTo方法肯定会报错啊(因为这时候找不到compareTo方法,未定义)
结合Test类中的compareTo方法,当this.age<o.age时,返回-1;
所以进入while循环,直到 a[runHi]).compareTo(a[runHi - 1])>=0时结束循环,后反转对象数组的lo~runHi-1部分
(ComparableTimSort.class)reverseRange(a, lo, runHi)的源码如下:
private static void reverseRange(Object[] a, int lo, int hi) { hi--; while (lo < hi) { Object t = a[lo]; a[lo++] = a[hi]; a[hi--] = t; } }
此时经过反转后数组变为了 2, 5, 6, 3, 1(这里没有写name属性),也就是前面3个对象是有序的,升序接下来我们就进入了下一个方法(ComparableTimSort.class)
我花了一点时间看了一下,就是C语言数据结构的二分排序法(也叫折半插入法,它是插入排序的一种改进版)
基本思想是:现将部分数组的部分元素变成一个有序的数组,后面的元素通过折半插入将它变成一个有序的数组。
例如前文:数组变成了2,5,6,3,1
则3插入前面有序的数组中,变成了 2,3,5,6,1
1在插入前面有序的数组中,变成了1,2,3,5,6
大家有时间可以去研究下。。这里不做详细说明。到了这里方法基本都跟进并介绍完了
输出结果:
1ii
2kk
3tt
5ss
6paul 升序。
那如何是降序呢?
修改Test类中的compareTo方法:
public int compareTo(Test o) { if (this.age > o.age) return -1; return 1; }
将返回值调换就行了,输出结果:
6paul
5ss
3tt
2kk
1ii 降序
关于compareTo方法的实现及返回值以下的组合,譬如:
public int compareTo(Test o) { if (o.age > this.age){ return 1; return -1; }
public int compareTo(Test o)
{
if (o.age > this.age)
return -1;
return 1;
}
那他们到底是升序还是降序呢?自己结合源码可以去思考一下。
但是上面两种不建议写,因为容易混淆。推荐写最上面两种。。。
写了这么多 总结一下:
//升序 public int compareTo(Test o) { if (this.age>o.age ){ return 1; return -1; } //降序 public int compareTo(Test o) { if (this.age > o.age) return -1; return 1; }
我自己记忆的方法是:
大于号 返回1,正乘正为正,所以升序(可以把>号想象为正)
大于号返回-1,正乘负为负,所以降序
提示非常重要的一点,compareTo中的方法一定要有至少两个以上(其实两个足够)的返回值,而且一个返回值一定要小于0,另一个一定要大于或等于0。
否则排序不会成功。自己结合ComparableTimSort.class的countRunAndMakeAscending方法分析。
最后留一个问题:我们说可以按照年龄属性进行降序升序排序,但比如有如下要求。
要求按照年龄大小升序排列,当年龄相同时,按照name属性降序排列,这时候compareTo函数怎么写呢?
大家可以去思考一下,这里我就不贴代码出来了,相信大家看过前文,自己思考一下应该可以写出来。
好了,这个博客写了好多小时了,该结束了,现在是北京时间22:25。撤了,撤了,大家晚安。
2017/6/19/ 22:25 ---祥子