Java集合之HashSet

首先上图:

 

由图可知,HashSet是Collection和Set接口的实现类。Set的一个重要特性就是元素不可重复,且元素无序(存入顺序与取出顺序不一致),这与List接口是恰恰相反的。HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能,其底层其实是一个HashMap的实例,它允许使用null元素HashSet不是线程安全的。Set集合和List集合存取元素的方式都一样,直接通过一个简单的样例来演示HashSet集合的用法:

package practice;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetPractice {
	public static void main(String args[]) {
		HashSet hs = new HashSet<>();
		hs.add("jack");//添加元素
		hs.add("eve");
		hs.add("rose");
		hs.add("rose");
		hs.add(null);//允许null元素
		Iterator it = hs.iterator();//获取迭代器
		while(it.hasNext())//遍历集合
			System.out.print(it.next()+" ");
		System.out.println();
	}
}


运行结果:null eve rose jack 

由结果可以看出取出元素的顺序与添加元素顺序并不一致,并且重复存入的字符串对象“rose”只添加了一次。那么HashSet是如何保证不出现重复元素的呢?是因为它在存入元素时做了很多工作。当调用add()方法存入元素时,1.调用当前要存入对象的hashcode()方法获得对象的哈希值,2.根据对象的哈希值计算出一个存储位置,3.若该位置上没有元素,则直接将元素存入。4.若该位置上有元素存在,则会调用equals()方法让当前要存入的元素和该位置上的元素进行比较,若返回false,则将该元素存入集合(说明元素不重复),若equals()方法返回true,则说明元素重复,丢弃该元素。

根据前面的分析不难看出,HashSet是通过hashCode和equals方法保证元素不重复的。因为String类已经重写了hashCode和equals方法,所以不需要再次重写。但如果向HashSet中存入自定义类对象,结果又会如何呢?看下面代码:

package practice;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetPractice {
	public static void main(String args[]) {
		HashSet<Student> hs = new HashSet<>();//new一个HashSet,泛型指定为自定义的类Student
		Student s1 = new Student(1, "Jack");
		Student s2 = new Student(2, "Rose");
		Student s3 = new Student(2, "Rose");
		hs.add(s1);//添加三个Student对象到集合中
		hs.add(s2);
		hs.add(s3);
		System.out.println(hs);//输出集合中的元素
	}
}
class Student{
	int id;
	String name;
	public Student(int id ,String name) {
		this.id = id;
		this.name = name;
	}
	public String toString() {//重写toString方法,方便集合输出
		return id+":"+name;
	}
}

运行结果:[2:Rose, 2:Rose, 1:Jack]

这时我们发现运行结果中出现了两个相同的学生信息“2:Rose”,按照HashSet的规则,这种应该会被视为重复元素,不能重复出现。那为何会出现这种情况呢?因为在定义Student类时,没有重写hashCode和equals方法。接下来对Student类进行改写,我们认为id相同就是同一个学生,改写后的代码如下:

package practice;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetPractice {
	public static void main(String args[]) {
		HashSet<Student> hs = new HashSet<>();//new一个HashSet,泛型指定为自定义的类Student
		Student s1 = new Student(1, "Jack");
		Student s2 = new Student(2, "Rose");
		Student s3 = new Student(2, "Rose");
		hs.add(s1);//添加三个Student对象到集合中
		hs.add(s2);
		hs.add(s3);
		System.out.println(hs);//输出集合中的元素
	}
}
class Student{
	int id;
	String name;
	public Student(int id ,String name) {
		this.id = id;
		this.name = name;
	}
	public String toString() {//重写toString方法,方便集合输出
		return id+":"+name;
	}
	public int hashCode() {
		/*
		 * 因为基本数据类型int没有hashCode方法,
		 * 所以将它转为Integer,在调用HashCode方法
		 */
		Integer t = id;
		return t.hashCode();
	}
	public boolean equals(Object obj) {
		if(obj == this)//若是同一个对象,直接返回true
			return true;
		if(!(obj instanceof Student))//若对象不是Student类型,返回false
			return false;
		Student stu = (Student)obj;//先将对象强制转换为Student
		return stu.id == this.id;//返回两个对象id比较后的结果
	}
}

运行结果:[1:Jack, 2:Rose]

发现结果正常了,因为重写了hashCode和equals方法,所以HashCode集合认为s2和s3两个对象是相同的,所以去掉了重复的对象。
 

 

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务