一、概述

  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:

 

  JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。

  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]
View Code

 

四、遍历集合

  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); 
}

  

posted on 2019-08-31 17:32  格物致知_Tony  阅读(886)  评论(0编辑  收藏  举报