• HashSet集合保证元素唯一性的原理 底层代码 ---有用


    分析com.itheima.demo01_set.Demo03类中的代码, 我们发现, HashSet集合保证元素唯一性的原理可能和 HashSet#add()方法相关, 于是源代码分析如下:

    //HashSet集合类中的代码.
    public class HashSet {

    //创建一个HashMap集合类对象.
    private transient HashMap<E,Object> map;
    //普通的Object类对象.
    private static final Object PRESENT = new Object();

    public HashSet() {
    map = new HashMap<>(); //结论1: HashSet集合底层依赖的是HashMap集合.
    }

    //HashSet集合添加元素的方法.
    public boolean add(E e) { //e: 表示要往集合中添加的元素.
    return map.put(e, PRESENT)==null;
    }
    }


    HashMap集合类中的源代码:
    public class HashMap {

    //key: 表示要往集合中添加的元素
    //value: new Object()
    public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
    }

    /*
    hash: 表示 要往集合中添加的元素的 哈希值.
    key: 表示 要往集合中添加的元素
    value: new Object()
    onlyIfAbsent: false
    evict: true
    */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    //初始化哈希表引用.
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //对哈希表做非空校验, 即记录哈希表的长度
    if ((tab = table) == null || (n = tab.length) == 0)
    n = (tab = resize()).length;
    //如果元素在哈希表中不存在, 就创建一个 节点记录该元素.
    if ((p = tab[i = (n - 1) & hash]) == null)
    tab[i] = newNode(hash, key, value, null);
    else {
    //走这里, 说明哈希表不为空, 即: 集合中已经有元素存在了.
    Node<K,V> e; K k;
    if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
    //走到这里, 说明是同一个元素, 不添加.
    else {
    //具体添加元素的动作......
    }
    .....
    }
    }

    通过观察源码, 我们发现, HashSet集合保证元素唯一性的原理, 和一个if判断相关, 我们详细看下这个判断:
    /*
    p: 集合中已经存在的元素.
    p.hash: 集合中已经存在的元素的 哈希值.

    hash: 表示 要往集合中添加的元素的 哈希值.
    key: 表示 要往集合中添加的元素

    */
    if ( true && ( false || ( true && false )))
    if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
    //走到这里, 说明是同一个元素, 不添加.
    else {
    //具体添加元素的动作......
    }

    分析上述判断的具体流程:
    1. 比较两个对象的哈希值是否相同.
    如果相同: 说明可能是同一个对象, 程序继续执行.
    如果不同: 说明不是同一个对象, 就添加.
    2. 比较两个对象的地址值是否相同.
    如果相同: 说明是同一个元素, 不添加.
    如果不同: 说明可能不是同一个元素, 程序继续执行.
    3. 判断要往集合中添加的元素是否为null
    如果是: 说明要往集合中添加的元素为null, 就添加.
    如果否: 说明可能不是同一个元素, 程序继续执行.
    4. 比较两个对象的各个属性值是否相同.
    如果相同: 说明是同一个元素, 不添加.
    如果不同: 说明不是同一个元素, 就添加.

    问: 要判断两个对象是否是同一个对象, 直接调用 equals()方法比较属性值不就行了吗, 为啥要设计的如何繁琐?
    答: 这样做的目的就是为了减少调用 equals()方法的次数, 从而节约资源, 提高效率.

  • 相关阅读:
    无服务器架构(Faas/Serverless)
    Cookie中的sessionid与JSONP原理
    requestAnimationFrame
    JS函数的防抖和节流
    JS 中的广度与深度优先遍历
    堆、栈和队列
    Java除法和js
    selected
    找jar包
    编辑器替换操作
  • 原文地址:https://www.cnblogs.com/shan13936/p/13850505.html
Copyright © 2020-2023  润新知