zoukankan      html  css  js  c++  java
  • Hashtable学习笔记

    Hashtable常用特点区分:    
    1、extends Dictionary ;
    2、线程安全;
    3、key和value!=null;
    4、默认容量11;负载因子0.75;
    5、容量扩展old<<2+1.
     
     /**
    *源码浅析
    */
    //继承Dictionary实现Map, Cloneable, java.io.Serializable
    public class Hashtable<K,V>
        extends Dictionary<K,V>
        implements Map<K,V>, Cloneable, java.io.Serializable
     
     
     
    //4个构造,同HashMap一样
     
     
    //第一个构造传入容量和负载因子
    public Hashtable(int initialCapacity, float loadFactor) {
            //传入容量不能小于0,
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            //负载因子不能小于等于0或者是非数
            if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new IllegalArgumentException("Illegal Load: "+loadFactor);
             //如果容量为0,则置为1,容量最小就是1
            if (initialCapacity==0)
                initialCapacity = 1;
            this.loadFactor = loadFactor;
              //table是以容量大小为初始大小的数组
            table = new Entry[initialCapacity];
             //临界值计算=容量乘以负载因子和当前系统数组最大长度加1的最小值,当达到临界值就需要扩容
            threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
            initHashSeedAsNeeded(initialCapacity);
        }
     
    // 添加初始的容量,负载因子默认0.75
    public Hashtable(int initialCapacity) {
            this(initialCapacity, 0.75f);
        }
    // 容器默认11,负载因子默认0.75
    public Hashtable() {
            this(11, 0.75f);
        }
    // 初始容器取map最大尺寸*2和11取大的,也就是最小也是11,负载因子0.75
    public Hashtable(Map<? extends K, ? extends V> t) {
            this(Math.max(2*t.size(), 11), 0.75f);
              //调用putAll将map中的数据加入hashtable中
            putAll(t);
        }
     
    //Hashtable大部分方法属性都是加了同步锁,所以Hashtable是线程安全的
     
    //返回所有key枚举对象
    public synchronized Enumeration<K> keys() {
            return this.<K>getEnumeration(KEYS);
        }
     
    //返回所有value枚举对象
    public synchronized Enumeration<V> elements() {
            return this.<V>getEnumeration(VALUES);
        }
     
    //判断Hashtable的值是否等于value
    public synchronized boolean contains(Object value) {
            //value不能等于null
            if (value == null) {
                throw new NullPointerException();
            }
            //遍历数组查找数组元素是否与value相等
            Entry tab[] = table;
            for (int i = tab.length ; i-- > 0 ;) {
                for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
                    if (e.value.equals(value)) {
                        return true;
                    }
                }
            }
            return false;
        }
     
    //判断Hashtable是否包含传入key
    public synchronized boolean containsKey(Object key) {
            Entry tab[] = table;
            //获取key的hash值
            int hash = hash(key);
            //计算在数组的索引
            int index = (hash & 0x7FFFFFFF) % tab.length;
            //找到key对应的链表,找出hash值和key值都相等的元素
            for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return true;
                }
            }
            return false;
        }
     
     
     //返回key对应的value,没有值得话返回null
     public synchronized V get(Object key) {
            Entry tab[] = table;
            //计算key对应的hash值
            int hash = hash(key);
            //根据hash计算对应的索引
            int index = (hash & 0x7FFFFFFF) % tab.length;
            //根据索引找到对应的链表,在链表中查找hash值和key值都相等的元素
            for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return e.value;
                }
            }
            return null;
        }
     
     
    //调整Hashtable的长度,使其达到(oldCapacity << 1) + 1
    protected void rehash() {
            int oldCapacity = table.length;
            Entry<K,V>[] oldMap = table;
     
            // overflow-conscious code
            int newCapacity = (oldCapacity << 1) + 1;
            if (newCapacity - MAX_ARRAY_SIZE > 0) {
                if (oldCapacity == MAX_ARRAY_SIZE)
                    // Keep running with MAX_ARRAY_SIZE buckets
                    return;
                newCapacity = MAX_ARRAY_SIZE;
            }
            Entry<K,V>[] newMap = new Entry[newCapacity];
     
            modCount++;
            //临界值=新容量*负载因子和数组元素实际容量加1的min
            threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
            boolean rehash = initHashSeedAsNeeded(newCapacity);
     
            table = newMap;
            //将原有元素复制到新的Hashtable中
            for (int i = oldCapacity ; i-- > 0 ;) {
                for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                    Entry<K,V> e = old;
                    old = old.next;
     
                    if (rehash) {
                        e.hash = hash(e.key);
                    }
                    //计算新索引
                    int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                    e.next = newMap[index];
                    newMap[index] = e;
                }
            }
        }
     
     
    //添加键值对
    public synchronized V put(K key, V value) {
            // value不等于null
            if (value == null) {
                throw new NullPointerException();
            }
     
            //若添加的key在Hashtable已经存在,则用新value覆盖原有的value
            Entry tab[] = table;
            int hash = hash(key);
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    V old = e.value;
                    e.value = value;
                    return old;
                }
            }
            //若不存在键值等于key的键值对,+1
            modCount++;
            //如果Hashtable实际容量大于临界值,扩容
            if (count >= threshold) {
                // Rehash the table if the threshold is exceeded
                rehash();
     
                tab = table;
                hash = hash(key);
                index = (hash & 0x7FFFFFFF) % tab.length;
            }
     
            // Creates the new entry.
            //将新的键值对插入对应数组索引为index的位置所在链表的表头.
            Entry<K,V> e = tab[index];
            tab[index] = new Entry<>(hash, key, value, e);
            count++;
            return null;
        }
     
     
    //删除键值为key的键值对
    public synchronized V remove(Object key) {
            Entry tab[] = table;
            int hash = hash(key);
            //计算索引
            int index = (hash & 0x7FFFFFFF) % tab.length;
            //因为是单链表,所以删除的时候要保留要删除节点的前一个节点
            for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    modCount++;
                    if (prev != null) {
                        prev.next = e.next;
                    } else {
                        tab[index] = e.next;
                    }
                    count--;
                    V oldValue = e.value;
                    e.value = null;
                    return oldValue;
                }
            }
            return null;
        }
     
    //多次调用put方法添加数据
    public synchronized void putAll(Map<? extends K, ? extends V> t) {
        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
            put(e.getKey(), e.getValue());
    }
     
    //通过遍历数组的方式将数组元素key值置为null,value不理会
    public synchronized void clear() {
            Entry tab[] = table;
            modCount++;
            for (int index = tab.length; --index >= 0; )
                tab[index] = null;
            count = 0;
        }
     
    //克隆Hashtable
    public synchronized Object clone() {
            try {
                //克隆一个相同的空Hashtable
                Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
                t.table = new Entry[table.length];
                //将原有元素一次克隆到相应位置
                for (int i = table.length ; i-- > 0 ; ) {
                    t.table[i] = (table[i] != null)
                        ? (Entry<K,V>) table[i].clone() : null;
                }
                //将延伸变量置空
                t.keySet = null;
                t.entrySet = null;
                t.values = null;
                t.modCount = 0;
                return t;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }
     
    //重写toString,遍历元素,生成{"key" = "value"},当长度达到最大值,结束
    public synchronized String toString() {
            int max = size() - 1;
            if (max == -1)
                return "{}";
     
            StringBuilder sb = new StringBuilder();
            Iterator<Map.Entry<K,V>> it = entrySet().iterator();
     
            sb.append('{');
            for (int i = 0; ; i++) {
                Map.Entry<K,V> e = it.next();
                K key = e.getKey();
                V value = e.getValue();
                sb.append(key   == this ? "(this Map)" : key.toString());
                sb.append('=');
                sb.append(value == this ? "(this Map)" : value.toString());
     
                if (i == max)
                    return sb.append('}').toString();
                sb.append(", ");
            }
        }
     
     
     
     
    业精于勤,荒于嬉;行成于思,毁于随;
  • 相关阅读:
    docker学习构建镜像---第三章节
    docker学习端口映射---第二章节
    推荐一个小而美的Python代码格式化工具
    Bi-LSTM+CRF在文本序列标注中的应用
    大数据分析师到底在干嘛
    Pytorch实现的语义分割器
    Python大数据与机器学习之NumPy初体验
    python数据分析工具——Pandas、StatsModels、Scikit-Learn
    Python修改paramiko模块开发运维审计保垒机
    Python数据预处理:使用Dask和Numba并行化加速
  • 原文地址:https://www.cnblogs.com/freedom-yuxin/p/7503611.html
Copyright © 2011-2022 走看看