首页 > 技术文章 > 判断对象相等以及相同对象问题——自定义类重写equals方法以及hashCode方法,以及遇到HashSet集合问题

xiatom 2019-04-17 18:12 原文

这篇文章主要针对HashSet、HashMap存储元素时,对元素要求,使用自定义类需要保证判断是否为同一对象,equals和hashCode都相等才能时同个对象。否则

  1. 两对象的equals方法相同,但是hashCode不同,那么HashSet就会存放在两个不同位置,那么就与Set规则冲突了(不能出现两个相同元素,这里的相同就是equals)
  2. 如果两对象hashCode相同,但是equals不同,那么就会采用哈希桶去保存多个对象,使得Hash性能下降

对象相等和是否为同意对象:

首先我们要注意,equals本身实现是为了判断两对象是否相等,但是有时我们需要根据需求使用equals判断两对象中的部分或全部属性是否相同,而非对象是否相同,所以就重写了equals方法。如String就重写了equals方法,根据字符串值判断是否相等,这很符合我们的思考方式,但是一定要注意这时equals就不能判断两个String对象是否为一个对象。如下:

public class equalTest {
	public static void main(String[] args) {
		String a = new String("x");
		String b = new String("x");
		System.out.println(a.equals(b));
		//输出结果为true,说明a和b字符串相同;
		
		System.out.println(a==b);
		//输出为false说明,a,b不是同一个对象
	}
}

下图就说明了这个问题,a和b指向的对象值相等,但是a,b指向的对象并不是同一个对象。
在这里插入图片描述


所以在我们自定义类的时候,可以根据需求重写equals方法,但是需要注意的是,像HashSet、HashMap这些集合类,如果存储我们的自定义类的对象时。由于这些集合不允许重复元素出现,所以判断元素标准要求equals方法相等并且hashCode方法相等

下面就是,两个不同的对象的equals方法和hashCode方法可能相同,

import java.util.HashSet;
public class Person {
	private String name;
	private int age;
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		Person other = (Person) obj;
		return this.name.equals(other.name);
	}
	
	public static void main(String[] args) {
		Person xb = new Person("xb", 20);
		Person ace = new Person("xb", 22);
		Person xiatom = new Person("xiatom", 20);
		
		System.out.println("xb的hashCode:"+xb.hashCode());
		System.out.println("ace的hashCode:"+ace.hashCode());
		System.out.println("xiatom的hashCode:"+xiatom.hashCode());
		
		System.out.println();
		System.out.println("xb与ace是否相同:"+xb.equals(ace));
		System.out.println("xb与xiatom是否相同:"+xb.equals(xiatom));
		System.out.println("xiatom与ace是否相同:"+xiatom.equals(ace));
	
		System.out.println();
		HashSet<Person> p = new HashSet<>();
		p.add(xb);
		p.add(xiatom);
		p.add(ace);
		System.out.println("输出HashSet");
		for(Person s:p)
			System.out.println(s);
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

运行结果如下:


可以看到,xb和ace对象相等,但是同时存到了HashSet集合中,这就出现了问题。
使用自定义类需要保证判断是否为同一对象,equals和hashCode都相等才能时同个对象。否则
1. 两对象的equals方法相同,但是hashCode不同,那么HashSet就会存放在两个不同位置,那么就与Set规则冲突了(不能出现两个相同元素,这里的相同就是equals)
2. 如果两对象hashCode相同,但是equals不同,那么就会采用哈希桶去保存多个对象,使得Hash性能下降

推荐阅读