zoukankan      html  css  js  c++  java
  • HashSet集合的add()方法的源码解析

    一般来说,不同的字符串的哈希值是不同的。

     1 package cn.itcast_02;
     2 
     3 /*
     4  *        一般来说,不同的字符串的哈希值是不同的。 
     5  *            哈希值仅仅是逻辑值,可能一样。
     6  *            地址值是实际的物理值,不一样。
     7  */
     8 
     9 public class HashCodeDemo {
    10     public static void main(String[] args) {
    11         System.out.println("hello".hashCode()); // 99162322
    12         System.out.println("hello".hashCode()); // 99162322
    13         System.out.println("world".hashCode()); // 113318802
    14     }
    15 }

     HashSet存储字符串并遍历

     1 package cn.itcast_02;
     2 
     3 import java.util.HashSet;
     4 
     5 /*
     6  * HashSet:存储字符串并遍历
     7  * 
     8  * 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
     9  *         通过查看add方法的底层源码,我们知道这个方法的底层依赖两个方法:hashCode()和equals()。
    10  *             即:
    11  *                int hashCode()
    12  *                boolean equals(Object obj)
    13  * 
    14  * 步骤:
    15  *         首先比较哈希值
    16  *             如果相同,继续走,比较地址值或者走equals()
    17  *             如果不同,就直接添加到集合中    
    18  * 
    19  * 按照方法的步骤来说:    
    20  *         先看hashCode()值是否相同
    21  *             相同:继续走equals()方法
    22  *                 返回true:说明元素重复,就不添加
    23  *                 返回false:说明元素不重复,就添加到集合
    24  *             不同:就直接把元素添加到集合中
    25  * 
    26  * 如果类没有重写这两个方法,默认使用的Object的方法。一般来说不相同。
    27  * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个元素。
    28  */
    29 public class HashSetDemo {
    30     public static void main(String[] args) {
    31         // 创建集合对象
    32         HashSet<String> hs = new HashSet<String>();
    33 
    34         // 创建并添加元素
    35         hs.add("hello");
    36         hs.add("world");
    37         hs.add("java");
    38         hs.add("world");
    39 
    40         // 遍历集合
    41         for (String s : hs) {
    42             System.out.println(s);
    43         }
    44     }
    45 }

    HashSet集合的add()方法的源码

    ---------------------------------------
    interface Collection {
        ...
    }
    
    interface Set extends Collection {
        ...
    }
    ---------------------------------------
    class HashSet implements Set {
        ...
        private static final Object PRESENT = new Object();
        private transient HashMap<E,Object> map;
        
        public HashSet() {
            map = new HashMap<>();
        }
        
        public boolean add(E e) { // e = hello,world
            return map.put(e, PRESENT)==null;
        }
        ...
    }
    ---------------------------------------
    class HashMap implements Map {
      ...
    public V put(K key, V value) { // key = e = hello,world // 看哈希表是否为空,如果是空,就开辟空间,开辟完空间,程序就往下走 if (table == EMPTY_TABLE) { inflateTable(threshold); } // 判断对象是否为null,不是null,程序就往下走 if (key == null) return putForNullKey(value); int hash = hash(key); // 和对象的hashCode()方法相关,即和对象的哈希值相关 int i = indexFor(hash, table.length); // 在哈希表中查找hash值 for (Entry<K,V> e = table[i]; e != null; e = e.next) { // 注意:这次的e其实是第一次/第二次的hello/world Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; // 走到这里说明没有添加元素 } } modCount++; addEntry(hash, key, value, i); // 把元素添加进集合 return null; } ... transient int hashSeed = 0; ... final int hash(Object k) { // k = key = e = hello, int h = hashSeed; // transient int hashSeed = 0; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // 这里调用的是对象的hashCode()方法 // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } ... } --------------------------------------- hs.add("hello"); hs.add("world"); hs.add("java"); hs.add("world"); ---------------------------------------
  • 相关阅读:
    build.gradle 详解(一)
    Android-SDK下目录结构
    eclipse中更新android SDK的方法(在线更新)
    mysql5.7安装
    DispatcherServlet 和 ContextLoaderListener 的关系,到底用哪个?
    IntelliJ IDEA WEB项目的部署配置
    IDEA 配置 tomcat的数据源
    magento后台使用POST表单时,要使用必要参数form_key才能正常通讯
    Atom安装以及activate-power-mode atom package插件安装
    linux下php-mysql拓展安装
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/8654871.html
Copyright © 2011-2022 走看看