近期工作需要,需要做一个简单的微信活动,主要是针对用户朋友圈答题,算出排名,在这个过程中,由于要用到根据score分数排名,刚开始我使用的是list,后来发现list的特性,去重稍微麻烦点,需要自己实现,从偷懒的角度出发,选择了既能去重,又能排序,还能偷懒的treeSet,结果自己调入了一个坑。只能说明自己的基础不够扎实,在这里总结下。
首先,由于业务的需要,需要一个集合来存储用户数据,那么用户数据必然是个对象。而且在容器中需要对这个对象进行去重和排序。这时候需要用到重写对象的equals方法。
public class User {
private String name ;
private Integer age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
首先看这部分,重写了hashCode和equals方法,至于为什么要这么写,可以参考我之前写的,对于hashCode和eaquals的实现的博文。
这样,声明一个Set来存储该容器。
TreeSet<User> userTreeSet =new TreeSet<User>();
此时不断往userTreeSet里加入User,如果name相同,那么会被当做同一个对象,此时会被替换掉。这样就实现了集合中的去重。测试代码如下:
import java.util.TreeSet;
import java.util.UUID;
import java.util.Map;
import java.util.HashMap;
import java.util.Formatter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
public class Testwei {
public static void main(String[] args) {
TreeSet<User> UserTreeSet =new TreeSet<User>();
for (int i = 10; i >0; i--) {
User u = new User();
u.setName("zhangsan"+i);
u.setAge(i);
UserTreeSet.add(u);
}
for (User u : UserTreeSet) {
System.out.println(u.getAge()+"====");
}
User u = new User();
u.setName("zhangsa2n"+9);
u.setAge(9);
UserTreeSet.add(u);
for (User au : UserTreeSet) {
System.out.println(au.getName()+au.getAge()+"====");
}
}
}
但是在这个基础上,此时还需要对这些用户的age根据从高到低的顺序进行排序,众所周知,treeSet默认的是自然排序,并不满足需求,那么如何进行倒序排序呢?此时用到了Comparable。实现该接口可以对用户进行排序。
此时方法如下:
public class User implements Comparable<Object>{
private String name ;
private Integer age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public int compareTo(Object paramT) {
// TODO Auto-generated method stub
int result = this.age-((User)paramT).getAge();
return result
}
}
看代码,此时再次运行Test方法,也的确对起哄的用户进行了重新的排序。但是此时发现了个问题。如果再加入一个用户,这个用户name不同,但是分数和其中某个用户相同,也就是说你compareTo方法返回的是0,会发现一个情况,这个用户在set里替换掉了原来的用户!!!
这就是我之前测试时出现的问题。
经过排查之后,也简单看了看Set的源码。
初步判断是这样的:Set集合在插入用户数据的时候,会调用compareTo方法进行比较,挨个元素进行比较,此时在conpareTo方法里,会调用对象的equals方法。如果两个对象相等,那么返回0,如果compareTo方法返回0.那么Set会认为这两个元素相同,这就是为什么之前会发现,重写compareTo方法之后,相同分数的用户反倒会被remove掉。
此时该重写compareTo方法的类变成了如下:
public class User implements Comparable<Object>{
private String name ;
private Integer age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public int compareTo(Object paramT) {
// TODO Auto-generated method stub
User u = (User)paramT;
if (paramT.equals(this)) {
return 0 ;
}
else {
int result = this.age-((User)paramT).getAge();
if (result==0) {
return 1;
}
else {
return result ;}}}}
其实在return的处理上肯定可以更加优化,限于时间,和项目赶,只能深入到这个程度。
因此要注意:在重写compareTo方法进行排序时,一定要记住:
1:如果返回0,那么新增的元素会替换掉之前的元素、
2:如果重写了compareTo方法,一定要记得对两个元素进行比较,如果不进行比较那么可能出现两种情况:1)Set中的元素去重功能失效。2)元素中相同分数的元素被替换。