Java自学笔记—HashSet

这篇博客详细介绍了Java中的HashSet,包括Set接口的特点、HashSet的底层实现(HashMap)、元素添加过程,以及equals()和hashCode()方法在HashSet中的作用。通过理解这些内容,读者可以更好地掌握HashSet的工作原理和使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java自学笔记—HashSet

Set接口特点

Set接口为Collection接口的一个子类

无序,没有索引
不允许重复,最多一个null
常用方法和Collection一样,但不能用索引获取元素

/**
 * @author Lspero
 * @version 1.0
 */
@SuppressWarnings("all")
public class SetMethod {
    public static void main(String[] args) {
        /*
         * 无序,没有索引
         * 不允许重复,最多一个null
         * 常用方法和Collection一样,但不能用索引获取元素
         * */
        Set set = new HashSet();
        //set接口实现类对象不能存放重复对象,可以添加一个null
        //数据存放时是无序的,但取出的顺序是固定的
        set.add("jhon");
        set.add("lucy");
        set.add("jhon");
        set.add("jack");
        set.add(null);
        set.add(null);
        System.out.println("Set = " + set);

        //遍历 迭代器和增强For循环
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }

        System.out.println("=========");
        for (Object o :set) {
            System.out.println(o);
        }
        //Set接口对象不能通过索引获取
    }
}

HashSet底层

HashSet底层是HashMap

/**
 * @author Lspero
 * @version 1.0
 */
public class HashSet_ {
    public static void main(String[] args) {

        Set hashSet = new HashSet();
        /* 1.HashSet实际上是HashMap,数组 + 链表
         public HashSet() {
              map = new HashMap<>();
          }
           2.可以存放一个null,不能有重复元素
           3.不保证元素是有序的,取决于hash后,再确定索引结果
        * */
        hashSet.add(null);
        //添加失败返回flase
        System.out.println(hashSet.add(null));
        System.out.println(hashSet);
    }
}

自定义一个类,数组 + 链表,模拟HashMap
数据结构示意如下图
在这里插入图片描述

/**
 * @author Lspero
 * @version 1.0
 */
public class HashSetStructure {
    public static void main(String[] args) {
        // 模拟HashMap底层(HashSet),数组 + 链表,为了提高效率

        //1.创建一个Node[]数组
        Node[] table = new Node[16];
        Node jhon = new Node("jhon", null);
        table[2] = jhon;
        Node jack = new Node("jack", null);
        jhon.next = jack;//将jack结点挂载到jhon
        Node rose = new Node("rose", null);
        jack.next = rose;//将rose结点挂载到jack

        Node lucy = new Node("lucy", null);
        table[3] = lucy;
        System.out.println("table = " + table);
    }
}

//结点,可以指向下一个结点,从而形成链表
class Node{
    Object item;
    Node next;

    public Node(Object item, Node next) {
        this.item = item;
        this.next = next;
    }
}

HashSet元素添加过程

添加元素过程
1. HashSet底层是HashMap
2. 添加一个元素,先得到hash值,然后转成索引值
3. 找到存储数据表table,看这个索引是否有已经存放的元素
4. 如果没有,则直接加入
5. 如果有,则调equals比较,如果相同,就放弃添加,如果不同,就添加到该条链表最后,equals可以重写
6. 在jdk8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认为8)
并且table大小>=MIN_TREEIFY_CAPACITY(默认为64),就会进行树化(红黑树)
如果链表到8,table没到64,会扩table

1. HsahSet底层为HashMap,第一次添加时,table数组扩容到16,临界值(threshold)为16加载因子(loadFactor = 0.75) = 12
2. 如果table使用到临界值12,就会扩容到16
2=32,新的临界值就是32*0.75=24,以此类推
3. 每加入一个Node(hash, key, vaule ,null)结点,size就会加一,不一定要同一链表,一共有12个后就开始扩容

equals()和hashCode()重写

重写equals()hashCode()方法可以指定类的具体实例是否能够加入Set

hashCode()返回该实例Hash值,经过add()方法确定该实例在table表中的索引

equals()用于判断两个实例是否为同一实例,即相同时是否加入链表

import java.util.HashSet;
import java.util.Objects;

/**
 * @author Lspero
 * @version 1.0
 */
public class HashSetExercise {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        //三个哈希值不同,一定可以添加
        //重写equals()和hashCode()后,第二个就添加不了
        hashSet.add(new Employee("milan", 18));
        hashSet.add(new Employee("smith", 18));
        hashSet.add(new Employee("milan", 18));
        System.out.println(hashSet);
    }
}

class Employee{
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }



    //如果name和age相同,则确定为相同对象,返回true
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age && Objects.equals(name, employee.name);
    }
    
    //如果name和age相同,则返回相同哈希值
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值