序
项目里有一个取数据的算法,返回List<Vo>这样的集合,返回的集合要求没有重复的对象且按发布时间做排序。
第一时间想到TreeSet这个数据结构。
一、对自定义对象去重
重写自定义对象的equals 和 hashCode方法
SUN官方的文档中规定
如果重定义equals方法,就必须重定义hashCode方法,以便用户可以将对象插入到散列(哈希)表中
那么 SUN 公司是出于什么考虑做了这个规定呢?
在集合框架中的HashSet,HashTable和HashMap
都使用哈希表的形式存储数据,而hashCode计算出来的哈希码便是它们的身份证。
哈希码的存在便可以:
- 1.快速定位对象,提高哈希表集合的性能。
- 2.只有当哈希表中对象的索引即hashCode和对象的属性即equals同时相等时,才能够判断两个对象相等。
- 3.从上面可以看出,哈希码主要是为哈希表服务的,其实如果不需要使用哈希表,也可以不重写hashCode。
- 4.但是SUN公司应该是出于对程序扩展性的考虑(万一以后需要将对象放入哈希表集合中),才会规定重写equals的同时需要重写hashCode,以避免后续开发不必要的麻烦。
重写equals的注意事项
Java语言规范要求equals需要具有如下的特性:
自反性:对于任何非空引用 x,x.equals()应该返回true。
对称性:对于任何引用 x 和 y,当且仅当y.equals(x)返回true,x.equals(y)也应该返回true。
传递性:对于任何引用 x、y 和 z,如果x.equals(y)返回true,y.equals(z)
也应返回同样的结果。
一致性:如果 x 和 y 引用的对象没有发生变化,反复调用x.equals(y)
应该返回同样的结果。
对于任意非空引用 x,x.equals(null) 应该返回false。
更多详细的说明请参考
Java 重写 equals 与 hashCode 的注意事项
这里我需要以主键文章ID为准来去重,对TopicVO对象复写hashCode和 equals方法:
@Override
public int hashCode()
{
return topicId.hashCode();
}
@Override
public boolean equals(Object obj) {
if(obj instanceof TopicVo) {
TopicVo vo = (TopicVo) obj;
return (vo.getTopicId().equals(this.getTopicId()));
}
return super.equals(obj);
}
二、对自定义对象排序
复写 compareTo方法,复写规则如下:
1.返回 1 那么当前的值会排在 被比较者 后面。
2.返回 0 那么当前的值【不会被加入到 TreeSet 中】,因为当前的值【被认为 是跟现有的某一个值相等】。
3.返回 -1 会被添加到 被比较者 的前边。
代码:
@Override
public int compareTo(Object obj) {
// TODO Auto-generated method stub
TopicVo o = (TopicVo) obj;
// 按照时间进行降序排列
if (this.getAuditAt().before(o.getAuditAt())) {
return 1;
}
if (this.getAuditAt().equals(o.getAuditAt()) && this.getTopicId().equals(o.getTopicId())) {
return 0;
}
return -1;
}
这里注意返回0的情况,有可能两条记录有同样的时间数据,因为要加上唯一标识TopicId也相等才能说明是同一条记录,不然有可能会丢失数据。
使用时直接把自定义对象TopicVo丢进去 TreeSet<TopicVo> 里就可以实现自动排序和去重了,这样子程序只需要专注于按照业务规则取数据就行了