zoukankan      html  css  js  c++  java
  • 关于HashMap,HashTable,HashSet浅析

     首先,最重要的,HashMap

     作为一个我们使用非常多的集合。最常被大家认知的是,它是一个key-value形式存储数据的数据结构,可以实现快速的存,取操作。
     关于HashMap的源码,我们截取一部分分析:
       
    public class HashMap<K,V>
        extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable
    {
    
        /**
        * The default initial capacity - MUST be a power of two.
        */
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    
        /**
        * The maximum capacity, used if a higher value is implicitly specified
        * by either of the constructors with arguments.
        * MUST be a power of two <= 1<<30.
        */
        static final int MAXIMUM_CAPACITY = 1 << 30;
    
        /**
        * The load factor used when none specified in constructor.
        */
        static final float DEFAULT_LOAD_FACTOR = 0.75f;
    
        /**
        * An empty table instance to share when the table is not inflated.
        */
        static final Entry<?,?>[] EMPTY_TABLE = {};
    
        /**
        * The table, resized as necessary. Length MUST Always be a power of two.
        */
        transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
    

      

       我们看到了它实现的接口有Serializable,说明他能序列化,有Cloneable,说明能被克隆,有Map<K,V>,说明是一个Map(废话)。还有几条有用的信息:第一:有个默认初始容量,第二:有个最大容量,第三:有个调节因子,第四:有个数组。
       再往后看,发现这玩意又是由一个数组组成的,而这个数组的初始容量是16,最大容量是2^30。当然这个调节因子这个地方暂且不提。
       既然是用数组存储,我们存的又是Key-Value形式,这数组是怎么运作的呢?这里用往Map中添加数据为例说明:
     
    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            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;
    } 
       由于篇幅问题,我们就不粘贴太多代码了,先说一下,我们的hashMap实现是有一个数组实现,数组中存储的都是Entry<Key,Value>节点,Entry是HashMap的内部类,存储的是key,value,key的哈希值和下一个节点,具体可以自己查看源码。
      这里我们看到,首先,如果这个数字为空,则先初始化一个数组,如果要添加的key为空,直接进行空Key的添加(这里HashMap是允许有一个key为空的值的)。如果key不为空,则算出key的哈希值,根据哈希值,查找对应数组的位置,如果此key存在,就是说有相同的key,则覆盖(其实是链到后面的串,每个数组元素往后一个链表),没有则直接添加。这么一说其实就简单了,我们查询什么的就可以根据哈希值直接定位到相应的Entry,然后扔出来就是了。
     

    然后我们说说HashSet:

     
    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable
    {
        static final long serialVersionUID = -5024744406713321676L;
    
        private transient HashMap<E,Object> map;
    
        // Dummy value to associate with an Object in the backing Map
        private static final Object PRESENT = new Object();
    
        /**
        * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
        * default initial capacity (16) and load factor (0.75).
        */
        public HashSet() {
            map = new HashMap<>();
        }

    这里就可以看出,HashSet底层就是一个HashMap,而它跟HashMap不同的就是它是实现Set接口,所以他的数据必须唯一。

     最后是HashTable:

     由于篇幅问题,就不贴代码了,跟HashMap差不多,底层也是一个数组。就说一下它跟HashMap主要的区别吧:
     第一:HashMap允许一个null的key和任意value都有null,而HashTable无论key和value都不能为空。
     第二:HashTable可以看做是线程安全的HashMap。
  • 相关阅读:
    hdu 6702 ^&^ 位运算
    hdu 6709 Fishing Master 贪心
    hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树
    hdu 1423 Greatest Common Increasing Subsequence 最长公共上升子序列 LCIS
    hdu 5909 Tree Cutting FWT
    luogu P1588 丢失的牛 宽搜
    luogu P1003 铺地毯
    luogu P1104 生日
    luogu P1094 纪念品分组
    luogu P1093 奖学金
  • 原文地址:https://www.cnblogs.com/jeyson/p/6425199.html
Copyright © 2011-2022 走看看