前面一篇,我们介绍了利用HashSet存储自定义对象的保证元素唯一性的优化过程。这篇,我们来阅读和解释下使用IDE快速生成重写equals和hashCode方法的代码。然后总结下HashSet保证存储元素唯一性的原理。

1.快速生成的equals和hashCode重写代码

      在IDE工具,我们可以使用alt+shift+s,然后点击h,可以快速生成自定义对象重写Object类的equals和hashCode方法。

@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		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;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

2.解释下hashCode中常量为什么是31这个数

       上面代码使用的prime=31,为什么需要使用31,而不是随便一个数字呢?主要有下面三个原因。

1)31是一个质数,只能被1和自己本身整除

2)31是一个不大也不小的质数

3)31是2的5次方减去1,利用位移操作能够快速得到结果,方便计算。

       质数可以减少公约数的个数,降低通过计算之后两个对象的哈希值还相等的概率。31作为一个不大,也不小的数,如果太大的质数,计算之后的结果可能大于int类型的最大表示范围。我们知道,计算机里面位移操作的计算速度是最快的。

3.给equals方法添加代码注释

@Override
	public boolean equals(Object obj) {
		if (this == obj)					//调用的对象和传入的对象是同一个对象
			return true;					//直接返回true
		if (obj == null)					//传入对象为null
			return false;					//返回false
		if (getClass() != obj.getClass())	//判断两个对象对应的字节码文件是否是同一个字节码(Java中内存中不可能存在两个相同的字节码文件)
			return false;					//如果不是直接返回false
		Person other = (Person) obj;		//上面的可能都排除,只能是符合类型传入,做强制转换,向下转型
		if (age != other.age)				//调用对象的年龄不等于传入对象的年龄
			return false;					//返回false
		if (name == null) {					//调用对象的姓名为null
			if (other.name != null)			//调用对象的姓名为null
				return false;				//返回false
		} else if (!name.equals(other.name))//调用对象的姓名不等于传入对象的姓名
			return false;					//返回false
		return true;						//前面判断都经历了,返回true
	}

4.HashSet原理

      我们使用Set集合都是需要去掉重复元素的,如果在存储的时候逐个equals()比较,效率比较低,哈希算法提高了去重复的效率,降低了使用equals()方法的次数。

       当HashSet调用add()方法存储对象的时候,先调用对象的hashCode()方法得到一个哈希值,然后在集合中查找是否有哈希值相同的的对象,如果没有哈希值相同的对象就直接存入集合;如果有哈希值相同的对象,就和哈希值相同的对象逐个进行equals()方法比较,比较结果为false就存入集合,true就不存入集合。

5.自定义对象存储HashSet去重的步骤

1)类中必须重写hashCode()和equals()方法
2)hashCode():属性相同的对象返回值必须相同,属性不同的返回值尽量不同(提高效率)
3)equals():属性相同返回true,属性不同返回false,返回false的时候存储到集合