一、概述
java.util.HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。
java.util.HashSet 底层的实现是一个 java.util.HashMap 支持。
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存储区和查找性能。保证元素唯一性的方式依赖于:hashCode 与 equals 方法。
特点:
1. 不允许存储重复的元素
2. 没有索引,也没有带索引的方法,不能使用普通 for 循环遍历
3. 是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4. 底层是一个哈希表结构(查询的速度非常的快)
二、HashSet 集合存储数据的结构
1、哈希值
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址)
在 Object 类中有一个方法,可以获取对象的哈希值。
int hashCode() 返回该对象的哈希码值。
hashCode 方法的源码:
public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
2、哈希表
在 JDK1.8 之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。
JDK1.8中(之后),哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
存储流程图:
Demo:
3、Set 集合不允许存储重复元素的原理
三、HashSet 存储自定义类型元素
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
Demo:
1 // 创建自定义 student 类 2 public class Student { 3 private String name; 4 private int age; 5 6 public Student() { 7 } 8 9 public Student(String name, int age) { 10 this.name = name; 11 this.age = age; 12 } 13 14 public String getName() { 15 return name; 16 } 17 18 public void setName(String name) { 19 this.name = name; 20 } 21 22 public int getAge() { 23 return age; 24 } 25 26 public void setAge(int age) { 27 this.age = age; 28 } 29 30 @Override 31 public boolean equals(Object o) { 32 if (this == o) 33 return true; 34 if (o == null || getClass() != o.getClass()) 35 return false; 36 Student student = (Student) o; 37 return age == student.age && 38 Objects.equals(name, student.name); 39 } 40 41 @Override 42 public int hashCode() { 43 return Objects.hash(name, age); 44 } 45 } 46 // 创建测试类 47 public class HashSetDemo2 { 48 public static void main(String[] args) { 49 //创建集合对象 该集合中存储 Student类型对象 50 HashSet<Student> stuSet = new HashSet<Student>(); 51 //存储 52 Student stu = new Student("于谦", 43); 53 stuSet.add(stu); 54 stuSet.add(new Student("郭德纲", 44)); 55 stuSet.add(new Student("于谦", 43)); 56 stuSet.add(new Student("郭麒麟", 23)); 57 stuSet.add(stu); 58 59 for (Student stu2 : stuSet) { 60 System.out.println(stu2); 61 } 62 } 63 } 64 执行结果: 65 Student [name=郭德纲, age=44] 66 Student [name=于谦, age=43] 67 Student [name=郭麒麟, age=23]
四、遍历集合
1、增强 for 循环
for (Integer i : set) {
System.out.println(i);
}
2、迭代器遍历
Iterator<Integer> it = set.iterator();
while (it.hasNext()){
Integer n = it.next();
System.out.println(n);
}