`
chenpenghui
  • 浏览: 37879 次
  • 性别: Icon_minigender_1
  • 来自: 台州
社区版块
存档分类
最新评论

通过set移除list相同项

    博客分类:
  • JAVA
阅读更多

今天按照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;
	}
	
	@Override
	public boolean equals(Object obj) {
		if((this.age).equals(obj.toString())){
			return true;
		}
		return false;
	}
	@Override
	public 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;
	}
	
	@Override
	public boolean equals(Object obj) {
		if((this.age).equals(obj.toString())){
			return true;
		}
		return false;
	}
	@Override
	public String toString() {
		return this.age;
	}
	
	
	
	@Override
	public 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失效,也就是:
	@Override
	public int hashCode() {
		return 1;
	}
 这样hashcode返回的值都一样,所以就不会直接加进去了,起作用的就是这个equals了。

至此。
从list中移除重复的项目,如果list装的是我们自己定义的类的对象,此类必须重写hashcode和equals方法,只有这样才能用set来移除重复项。感谢“http://www.blogjava.net”的“我思故我强”。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics