通过set移除list相同项
今天按照boss的要求做的时候,遇到了一个问题。boss一条记录里只要A,B,C三个条件相等的时候,这条记录也就相等,删掉重复的两条,保留一条。于是心想,数据量比较大,只取一次数据,然后在对这些数据进行处理后,用到不同的输出里,应该问题不大,既然是实体类,那么就重写一下equals方法,然后用set去装原来的list就成了。文字表达不好,下面就举例子吧。
比如如下实体类:
?
public class T {String name;Date sDate;Date eDate;String age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getsDate() {return sDate;}public void setsDate(Date sDate) {this.sDate = sDate;}public Date geteDate() {return eDate;}public void seteDate(Date eDate) {this.eDate = eDate;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}@Overridepublic boolean equals(Object obj) {if((this.age).equals(obj.toString())){return true;}return false;}@Overridepublic String toString() {return this.age;}}
?
?重写了equals和tostring方法,以为成功大吉了。
于是测了一把(代码如下):
?
class tt{public static void main(String[] args) throws Exception {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");T t1 = new T();t1.setAge("1");t1.setsDate(sdf.parse("2012-02-01 02:02:02.0"));t1.setName("a");T t2 = new T();t2.setAge("1");t2.setsDate(sdf.parse("2012-02-01 02:02:02.0"));t2.setName("b");boolean b12 = t1.equals(t2);T t3 = new T();t3.setAge("1");t3.setsDate(sdf.parse("2012-02-01 02:02:02.0"));t3.setName("c");T t4 = new T();t4.setAge("2");t4.setsDate(sdf.parse("2012-02-01 02:01:02.0"));t4.setName("d");boolean b34 = t3.equals(t4);T t5 = new T();t5.setAge("2");t5.setsDate(sdf.parse("2012-02-01 02:01:02.0"));t5.setName("e");List<T> list = new ArrayList<T>();list.add(t1);list.add(t2);list.add(t3);list.add(t4);list.add(t5);Set<T> set = new HashSet<T>();for(T t:list){System.out.println(set.add(t));}System.out.println(set.size());}}?
?
输出:
true
true
true
true
true
5
当时就郁闷了,set咋就全部把记录都插进去了呢。
当时还不信了,又写了一个玩样来测试。
?
?
public class T1 {public static void main(String[] args) {T1 t = new T1();t.test();}public void test(){String str1 = "1";String str2 = "1";String str3 = "2";String str4 = "2";String str5 = "1";List list = new ArrayList();list.add(str1);list.add(str2);list.add(str3);list.add(str4);list.add(str5);HashSet set = new HashSet(list);System.out.println(set.size());}}
?
?输出:2
这又正确的。
查阅了网上资料发现:
原来set的不重复是这样实现的:
第一步1.计算即将放进去的对象的hashcode,如果计算出的这个位置里没有对象,set就认为这对象并不存在,于是直接加进去了。注意!是直接加进去了,不管equals了。
第二部2.如果在1中计算出的hashcode的位置中有一个对象了,那么set会去找equals方法了,此时如果equals返回true就不加了,返回false,再进行一次散列,将该对象放到散列后计算出的新地址里,于是就加进去了。
总结一下:在java集合中,判断两个项相等是这样的:
?
附件图片(其实就是上面的第一步和第二步不看也罢)
于是重写了equals,必须重写hashcode,因为string是重写过这两个方法,因此刚才第二个测试set没有把相同的加进去,而我们有时候写的实体类没重写hashcode,new一个对象的时候,hashcode不同,那么set就全部都可以加进去了。
于是重写改写了上面的方法:
?
public class T {String name;Date sDate;Date eDate;String age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getsDate() {return sDate;}public void setsDate(Date sDate) {this.sDate = sDate;}public Date geteDate() {return eDate;}public void seteDate(Date eDate) {this.eDate = eDate;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}@Overridepublic boolean equals(Object obj) {if((this.age).equals(obj.toString())){return true;}return false;}@Overridepublic String toString() {return this.age;}@Overridepublic int hashCode() {return Integer.parseInt(this.age);}}class tt{public static void main(String[] args) throws Exception {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");T t1 = new T();t1.setAge("1");t1.setsDate(sdf.parse("2012-02-01 02:02:02.0"));t1.setName("a");T t2 = new T();t2.setAge("1");t2.setsDate(sdf.parse("2012-02-01 02:02:02.0"));t2.setName("b");boolean b12 = t1.equals(t2);T t3 = new T();t3.setAge("1");t3.setsDate(sdf.parse("2012-02-01 02:02:02.0"));t3.setName("c");T t4 = new T();t4.setAge("2");t4.setsDate(sdf.parse("2012-02-01 02:01:02.0"));t4.setName("d");boolean b34 = t3.equals(t4);T t5 = new T();t5.setAge("2");t5.setsDate(sdf.parse("2012-02-01 02:01:02.0"));t5.setName("e");List<T> list = new ArrayList<T>();list.add(t1);list.add(t2);list.add(t3);list.add(t4);list.add(t5);Set<T> set = new HashSet<T>();for(T t:list){System.out.println(set.add(t));}System.out.println(set.size());}}
?
?多写了一个hashcode()
运行一下 输出:
true
false
false
true
false
2
?这下对了。后来看了网上又发现一个法子,让hashcode失效,也就是:@Overridepublic int hashCode() {return 1;}?这样hashcode返回的值都一样,所以就不会直接加进去了,起作用的就是这个equals了。