Vector底层结构和源码剖析| HashSet底层机制说明(看源码)

62 阅读3分钟

Vector底层结构和源码剖析

Vector底层结构和ArrayList的比较

查看源码和上一篇的差不多一样一样的,只不过扩容机制这里有点不一样。

就扩容了

双链表LinkedList

关于双链表的基础知识我以前做过笔记可以看一下mp.weixin.qq.com/s/fVGp6fJx2…

Set接口和常用方法和List Collection的一毛一样遍历方式也是

不能使用索引的方式来获取.

Set接口实现类- HashSet

HashSet底层机制说明(看源码)

分析HashSet的添加元素底层是如何实现

预留的一个安全空间

剩下的不看了,step out出去

这能看到给加进去了

这能看到给加进去了

HashSet set = new HashSet();
        set.add("gjy");
        set.add("php");
        System.out.println(set);
        /*
        1 执行
        public HashSet() {
        map = new HashMap<>();
    }
        2 执行add()
        public boolean add(E e) {// e="gjy"
        return map.put(e, PRESENT)==null;
    }
        3 执行put() 该方法会执行hash(key) 得到key对应的hash值,算法h = key.hashCode()^(h >>> 16)
         public V put(K key, V value) {//key = "gjy" value = PRESENT
        return putVal(hash(key), key, value, false, true);
    }
        4 执行putVal
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//这里定义了辅助变量

        //tabLe 就是HashMap 的一个数组,类型是Node []
        if ((tab = table) == null || (n = tab.length) == 0)//if语句表示如果当前table是null,或者大小=0
            n = (tab = resize()).length; //就是第一次扩容,到16个空间。

         //根据key,得到hash去计算该key应该存放到tabLe表的哪个索引位置
        if ((p = tab[i = (n - 1) & hash]) == null) //并把这个位置的对象,赋给p
        //(2)判断p是否为null
        //(2.1) 如果p为null, 表示还没有存放元素,就创建一个Node (key = "gjy" value = PRESENT)
            tab[i] = newNode(hash, key, value, null);//(2.2) 就放在该位置
        else {//一个开发技巧提示:在需要局部变量(辅助变量)时候,在创建
            Node<K,V> e; K k;
            //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
            //并且满足 下面两个条件之
            if (p.hash == hash && //(1) 准备加入的key和p指向的Node结点的key 是同一个对象
                ((k = p.key) == key || (key != null && key.equals(k))))//(2) p指向的Node结点的key的equals()和准备加入的key比较后相同
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }

还有好多分析不下去了

分析HashSet的扩容和转成红黑树机制

看源码

按照这样依次类推


链表元素到8个之后再加元素到这一条链表的话,数组会自动扩容,直到满足树化的条件

Set接口实现类- LinkedHashSet

后面的自己去看一下

练习题

定义一个Employee类,该类包含: private成员属性name,age要求: 1.创建3个Employee放入HashSet中 2.当name和age的值相同时,认为是相同员工,不能添加到HashSet集合中

...

public class hashset {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        HashSet set = new HashSet();
        set.add(new Employee("yjg",54));
        set.add(new Employee("htf",23));
        set.add(new Employee("htf",23));//重写之前加入三个,重写之后这个加入不成功
        System.out.println(set);
    }
}

class Employee {
    //属性
    //构造器
    //getter setter
    //to String
    
    //重写 alt+insert equals...
    //如果name和age相同时,则返回相同的hash值
    @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);
    }

    @Override
    public int hashCode() {
        //这可以追一下源码hash
        return Objects.hash(name, age);
    }
}

要使属性的值相同时不能加入到集合中就chong'xie重写equals就行(alt+insert)linkedlist一样