概述
- HashSet集合里面的元素不允许重复,而且存储没有顺序
- 没有索引,不可以使用普通for循环遍历,但可以使用正确for循环—>foreach遍历。可以使用迭代器iterator()进行迭代遍历,但要注意并发异常问题。
- 底层是使用hash表进行存储的,哈希表是由数组+链表实现的。JDK1.8后,在存储数量少于8个,就还是原来的数组+链表。多于8个元素后,就是数组+红黑树。
存储原理
- 首先,根据存储元素,调用其元素的hashCode()方法,获得其哈希值
- 根据哈希值,在数组的下标为哈希值的位置上,查看是否存在元素。如果没有元素就直接存储进去
- 如果对应位置有元素,就调用其equals()方法,比较它们的值,看是否相等,相等就不添加,不相等就添加
- 示例代码
import java.util.*;
//类A重写了equals方法
class A
{
public boolean equals(Object obj){
return true;
}
}
//类B重写了hasCode()方法
class B
{
public int hashCode()
{
return 1;
}
}
//类C重写了equals(),hasCode()方法,让它们都返回相同的true,hasCode值
class C
{
public int hashCode(){
return 2;
}
public boolean equals(Object obj){
return true;
}
}
@SuppressWarnings("unchecked")
public class HashSetTest
{
public static void main(String[] args){
HashSet books = new HashSet();
//往hashSet对象添加对象,
//1.HahSet会调用该对象的hashCode()方法来得到该对象的hashCode值
//然后根据该对象的hashCode值决定该对象在hashSet的存储位置
//2.如果该对象的equals返回值是true,表示这两个对象相等,但hashCode不一样,一样存储
//3.HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的 //hashCode()方法返回值也相等。
//一般内置的方法,在它们true时,就处理了,令其hashCode相同,因此不能在set存储相同元素
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
System.out.println(books);
}
}
- 结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/417c5773c3c840bf9f6e5d84724d6b8a.png)
- 理解:由于A类只重写其equals()方法,虽然它返回的是true,但首先是调用其hashCode()方法,默认是返回其地址值,由于是new了两个A对象,所以其哈希值不一样,所以就添加进去
- 理解:B类只重写了其hashCode()方法,因为返回的哈希值相等,就比较其是否相等,调用equals()方法,返回fasle,其不相等,就添加进入,虽然在同一个位置
- 理解:C类重写了equals()和hashCode()方法,首先添加两个C对象进去时,它们的哈希值相等,再调用其equals(),其返回true,即重写的equals()认为它们相等,因此只添加了第一个。
注意
- 如果需要把某个类的对象保存到HashSet集合中,重写这个类的equals()方法和hashCode()方法时,应该尽量保证两个对象通过equals()方法比较返回true时,它们的hashCode()方法返回值也相等。