对自定义类的排序方法:
在现实生活中,我们需要对很多信息进行相应的排序,然后呈现给大家查看,有些数据是可以直接排序的,比如说我们最常见的数字,可以按照升序或者降序的方法来进行排列,又比如说日期,可以按照时间的远近来进行排序。这些都是最为常见的信息排序。
但是生活中会有许多信息并不能通过这种简单的方法来进行处理。举个例子:新闻信息,它的排序规则可能是这样的:先按照发布时间进行排列,把最新的新闻放在首页,再按照点击率进行排列,再按照标题进行排列,等等排列因素放在一起,形成我们最后看到的消息顺序。所以我们在做相应的信息处理时,我们需要想办法来解决这些消息的排序问题。再或者说当我们打开淘宝网站时,呈现给我们的商品可能是按照多种排序规则最后呈现出来的结果。比如先按照商品的收藏量进行降序排列,再按照相关度进行降序排列,再按照价格等诸多因素进行排序(这些排序只是个人的猜测,不代表真实情况啊,别被我误导了,实际情况会比这些复杂)。这些现实中的实体类的排序规则就需要考虑到更多的规则来进行操作。这周学习到了两种方法,对我们的自定义类进行排序。如下所示:
方法1、在实体类中实现java.lang.comparable接口,然后重写相应的compareTo方法,下面结合一个实例来进行解释:
1)首先我们自己定义一个新闻类,主要属性就是标题、发布时间、以及点击率
package com.peng01.sort.refType;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 新闻条目的实体类
* 使用Comparable接口
*/
public class NewsItem implements java.lang.Comparable<NewsItem>{//实现comparable接口
private String title;//新闻标题
private Date pubTime;//新闻发布的时间
private int hits;//新闻的点击率
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getPubTime() {
return pubTime;
}
public void setPubTime(Date pubTime) {
this.pubTime = pubTime;
}
public int getHits() {
return hits;
}
public void setHits(int hits) {
this.hits = hits;
}
public NewsItem(String title, Date pubTime, int hits) {
super();
this.title = title;
this.pubTime = pubTime;
this.hits = hits;
}
public NewsItem() {
}
// 按照发布时间降序+点击率降序+新闻标题升序
@Override
public int compareTo(NewsItem o) {//重写comparable接口中的compare方法
int result;
result = -this.pubTime.compareTo(o.pubTime);//默认的是升序,所以加一个负号成为降序
if(0 == result) {//时间相同
//然后看点击量
result = -(this.hits-o.hits);//点击率为降序
if(0 == result) {//点击量相同
//然后看标题
result = this.title.compareTo(o.title);//标题按照升序
}
}
return result;
}
@Override
public String toString() {//重新toString方法
StringBuilder sb = new StringBuilder();
sb.append("标题:").append(this.title);
sb.append(",时间:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.pubTime));
sb.append(",点击率:").append(this.hits).append("\n");
return sb.toString();
}
}
我将整个代码都放上去了,为了方便大家看清楚一点,我把核心代码单独拿出来给大家分析:
// 按照发布时间降序+点击率降序+新闻标题升序
@Override
public int compareTo(NewsItem o) {//重写comparable接口中的compare方法
int result;
result = -this.pubTime.compareTo(o.pubTime);//默认的是升序,所以加一个负号成为降序
if(0 == result) {//时间相同
//然后看点击量
result = -(this.hits-o.hits);//点击率为降序
if(0 == result) {//点击量相同
//然后看标题
result = this.title.compareTo(o.title);//标题按照升序
}
}
return result;
}
这段代码就属于使用java.lang.comparable+compareTo方法中最为核心的代码,需要在业务实体类中重写compare方法,直接将该新闻类别的排序规则放入其中。
2)我们来测试一下我们的新闻排序:
package com.peng01.sort.refType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class NewsApp {
public static void main(String[] args) {
List<NewsItem> list = new ArrayList<NewsItem>();
list.add(new NewsItem("中国",new Date(System.currentTimeMillis()),100));
list.add(new NewsItem("美国",new Date(System.currentTimeMillis()-1000*60*60),50));
list.add(new NewsItem("俄罗斯",new Date(System.currentTimeMillis()+1000*60*60),800));
list.add(new NewsItem("日本",new Date(System.currentTimeMillis()+1000*60*60),60));
System.out.println("排序前:"+list);
Collections.sort(list);//直接依靠NewsItem中设定好的compareTo的规则进行比较
System.out.println("排序后:"+list);
}
}
在java中,时间的计算是使用毫秒来进行计算的,所以信息“中国”的时间是当前时间,“美国”是一小时之前,“俄罗斯”和“日本”的发布时间是一小时之后。相应的点击率也设置的有所不同。
3)查看一下我们的运行结果:
排序前:[标题:中国,时间:2019-01-20 09:26:42,点击率:100
, 标题:美国,时间:2019-01-20 08:26:42,点击率:50
, 标题:俄罗斯,时间:2019-01-20 10:26:42,点击率:800
, 标题:日本,时间:2019-01-20 10:26:42,点击率:60
]
排序后:[标题:俄罗斯,时间:2019-01-20 10:26:42,点击率:800
, 标题:日本,时间:2019-01-20 10:26:42,点击率:60
, 标题:中国,时间:2019-01-20 09:26:42,点击率:100
, 标题:美国,时间:2019-01-20 08:26:42,点击率:50
]
可以观察得到:首先是按照时间的最近原则进行排序,所以“俄罗斯”和“日本”的排列被放在了最前面,当时间相同时,再按照点击率进行排序,所以“俄罗斯”的点击率最高,被排列在了最前面。大家感兴趣的话可以将上面的源码直接复制,便可以运行。这个实例在排序的时候由于信息较少,还没有对标题进行排序,因为前两个时间和点击率已经完成了相应的排序规则。特此说明一下相应的标题排序,在对字符进行排序的时候,是根据计算机中的Unicode编码计算每一个字符的值,然后根据大小进行排序。
方法2、在业务类排序中使用java.util.comparactor接口,然后再自己根据需求定义相应的业务实体类compare方法。同样结合一个实例来进行讲解:
1)首先定义一个商品类:
public class Goods {
private String name;//商品名称
private int fav;//收藏量,喜爱
private double price;//价格
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("商品名称:").append(this.name).append("\t");
sb.append("收藏量:").append(this.fav).append("\t");
sb.append("价格:").append(this.price).append("\t").append("\n");
return sb.toString();
}
}
由于篇幅的限制,我们就把相应的构造器还有set,get方法都省略了吧!可以看出,这个商品类是一个很纯净的简单类,里面不具有任何华丽的方法,此处重写了toString 方法是为了后续的显示好看一点,毕竟技术很重要,颜值也很重要哈!对吧!
2)然后我们再来定义两个比较器:
关于收藏量的比较器:
package com.peng01.sort.refType;
/**
* 使用Comparator接口,设计一个专门用于价格的比较器
* 按收藏量进行排序的业务类(升序)
*/
public class GoodsFavComp implements java.util.Comparator<Goods>{//实现comparator接口
//价格按照降序来进行排列
@Override
public int compare(Goods o1, Goods o2) {//重写compare方法
double p1=o1.getFav();
double p2=o2.getFav();
return -((p1-p2)>0?1:((p1-p2)==0?0:-1));//默认是升序,现在取-1进行降序
}
}
关于价格的比较器:
package com.peng01.sort.refType;
/**
* 使用Comparator接口,设计一个专门用于价格的比较器
*/
public class GoodsPriceComp implements java.util.Comparator<Goods>{
//价格按照降序来进行排列
@Override
public int compare(Goods o1, Goods o2) {
double p1=o1.getPrice();
double p2=o2.getPrice();
return -((p1-p2)>0?1:((p1-p2)==0?0:-1));//默认是升序,现在取-1进行降序
}
}
3)现在我们来跑一下我们的主程序:
package com.peng01.sort.refType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class GoodsApp {
public static void main(String[] args) {
List<Goods> goods = new ArrayList<Goods>();
goods.add(new Goods("巧克力",3200,120));
goods.add(new Goods("饼干",1300,10));
goods.add(new Goods("番茄",3465,60));
goods.add(new Goods("蔬菜",45634,54));
goods.add(new Goods("包子",54564,14));
System.out.println("排序前:"+"\n"+goods);
Collections.sort(goods, new GoodsPriceComp());//依赖自己设定的GoodsPriceComp进行比较
System.out.println("按照价格排序后:"+"\n"+goods);
Collections.sort(goods, new GoodsFavComp());//依赖自己设定的GoodsPriceComp进行比较
System.out.println("按照收藏排序后:"+"\n"+goods);
}
}
现在我们来查看一下运行结果:
排序前:
[商品名称:巧克力 收藏量:3200 价格:120.0
, 商品名称:饼干 收藏量:1300 价格:10.0
, 商品名称:番茄 收藏量:3465 价格:60.0
, 商品名称:蔬菜 收藏量:45634 价格:54.0
, 商品名称:包子 收藏量:54564 价格:14.0
]
按照价格排序后:
[商品名称:巧克力 收藏量:3200 价格:120.0
, 商品名称:番茄 收藏量:3465 价格:60.0
, 商品名称:蔬菜 收藏量:45634 价格:54.0
, 商品名称:包子 收藏量:54564 价格:14.0
, 商品名称:饼干 收藏量:1300 价格:10.0
]
按照收藏排序后:
[商品名称:包子 收藏量:54564 价格:14.0
, 商品名称:蔬菜 收藏量:45634 价格:54.0
, 商品名称:番茄 收藏量:3465 价格:60.0
, 商品名称:巧克力 收藏量:3200 价格:120.0
, 商品名称:饼干 收藏量:1300 价格:10.0
]
有没有感觉很爽啊!清爽得不得了!哈哈!we succeeded !
总结:
方法1:java.lang.comparable+compareTo
方法2:java.util.comparator+compare
比较:通过上面的实例可以发现,方法1,在实现的时候,需要在业务实体类中一次性将所有的排序规则实现,后期加入需要加入新的排序元素,将会改动源代码,并不具有低耦合的效果。方法2,在实现的时候,对于业务类的定义是一个很清洁简单的一个类别,在我们需要对信息进行排序的时候,我们只需要重新写一个比较器compare就可以了,然后再单独加入相应的主程序中即可,具有解耦的效果,并且更加灵活易于处理多变的排序规则。
对上述内容有疑问的同学,可以在文章下面留言啊!我们一起讨论,一起进步!