hashmap与hashtable

HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,HashSet 是 Set 接口的常用实现类。

HashMap
HashMap具有以下特点
基于数组+链表实现,数组里的元素是一个单向链表。
键不可以重复,值可以重复,键、值都可以为null
非线程安全
实现了Map, Cloneable, Serializable接口
成员变量

static final int DEFAULT_INITIAL_CAPACITY = 16;// 默认初始容量为16,必须为2的幂  

static final int MAXIMUM_CAPACITY = 1 << 30;// 最大容量为2的30次方  

static final float DEFAULT_LOAD_FACTOR = 0.75f;// 默认加载因子0.75  

transient Entry<K,V>[] table;// Entry数组,哈希表,长度必须为2的幂  

transient int size;// 已存元素的个数  

int threshold;// 下次扩容的临界值,值为初始容量*加载因子;size>=threshold就会扩容  

final float loadFactor;// 加载因子,手动设置的加载因子  

transient int modCount;//改变次数

static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;//默认阀值

构造方法

//传入容量与加载银子
public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        this.loadFactor = loadFactor;
        threshold = initialCapacity;
        init();
    }
//传入容量
 public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
//无参构造
public HashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }
//传入一个map
public HashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        inflateTable(threshold);
        putAllForCreate(m);
    }

size
返回当前长度

 public int size() {
        return size;
    }

isEmpty
判断当前是否为空

 public boolean isEmpty() {
        return size == 0;
    }

hash
计算hash

 final int hash(Object k) {

        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

put

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
/*如果key为null则调用  putForNullKey(value) 函数 这个函数先在table[0]这条链上找有没有key 为null的元素如果有就覆盖,如果没有就新建一个new一个key为null,value=value hash=0,的Entry放在table[0]。
*/     
        int hash = hash(key);
//获得key的hash值                        
        int i = indexFor(hash, table.length);
//由hash值确定放在table表中的那一条链上。类似于取模后放在数组中的哪个位置。        
        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;
     //如果链上原来有一个hash值相同,且key相同的则用新的value值进行覆盖。           
            }
        }
//否则利用hash,key,value,new一个Entry对象插入到链表中。
        modCount++;
        addEntry(hash, key, value, i);
        return null;

    }

putForNullKey
将key为null的键值对插入0好位置

private V putForNullKey(V value) {

        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

indexFor
这里用&代替了%,提高了效率
返回某个对象的下标

 static int indexFor(int h, int length) {
                return h & (length-1);
    }

get
通过key查询value

 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        //获取Entry
        Entry<K,V> entry = getEntry(key);
        //返回值
        return null == entry ? null : entry.getValue();
    }

getForNullKey
获取key为null的值

 private V getForNullKey() {
        if (size == 0) {
            return null;
        }

        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }

containsKey
是否存在某个key

public boolean containsKey(Object key) {

        return getEntry(key) != null;
    }

containsValue
是否存在某个值

 public boolean containsValue(Object value) {

        if (value == null)
            return containsNullValue();

        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (value.equals(e.value))
                    return true;
        return false;
    }

resize
扩容

  void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }
        //新的数组
        Entry[] newTable = new Entry[newCapacity];
        //将原数组复制,获取到新的hash掩码然后重新哈希
        transfer(newTable, initHashSeedAsNeeded(newCapacity));
        //切换table
        table = newTable;
        //更改阀值
        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
    }

remove
通过key删除value

public V remove(Object key) {
        Entry<K,V> e = removeEntryForKey(key);
        return (e == null ? null : e.value);
    }

clear
清空

 public void clear() {
        modCount++;
        Arrays.fill(table, null);
        size = 0;
    }

hashtable
特点:
1,基于数组+链表实现,是一个双向链表
2,线程安全
3,实现了Map, Cloneable, java.io.Serializable接口

成员变量

private transient Entry<K,V>[] table;

     private transient Entry[] table;   // 由Entry对象组成的链表数组


    private transient int count;   // Hashtable中Entry对象的个数

       private int threshold;   // Hashtable进行扩容的阈值

    private float loadFactor;   // 加载因子,默认为0.75


    private transient int modCount = 0;   // 记录Hashtable修改的次数

    private static final long serialVersionUID = 1421746759512286392L;

    static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;


构造函数

//指定容量大小和加载因子的构造方法

    public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        //创建hash数组
        table = new Entry[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        useAltHashing = sun.misc.VM.isBooted() &&
                (initialCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
    }


     // 指定容量大小和默认加载因子(0.75)的构造方法

    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }


     // 指定默认初始容量(11)和默认加载因子(0.75)的构造方法
        public Hashtable() {
        this(11, 0.75f);
    }


     // 带有Map参数的构造函数

    public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        //将map中的所有元素加入到Hashtable中
        putAll(t);
    }

size
返回元素数量

public synchronized int size() {
        return count;
    }

isEmpty
判断是否为空

 public synchronized boolean isEmpty() {
        return count == 0;
    }

contains
判断Hashtable中是否包含值为value的元素,

 public synchronized boolean contains(Object value) {
        if (value == null) {//Object为null,则抛出空指针
            throw new NullPointerException();
        }

        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;
    }

containsValue
判断是否存在某个值

 public boolean containsValue(Object value) {
        return contains(value);
    }


containsKey
判断是否存在某个key

public synchronized boolean containsKey(Object key) {
        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)) {
                return true;
            }
        }
        return false;
    }

get
通过key获取value

public synchronized V get(Object key) {
        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)) {
                return e.value;
            }
        }
        return null;
    }

rehash
进行扩容

 protected void rehash() {
        //旧数组大小oldCapacity
        int oldCapacity = table.length;
        Entry<K,V>[] oldMap = table;

        // 新数组长度 = 旧数组长度*2 + 1
        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];
        //修改次数+1
        modCount++;
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        boolean currentAltHashing = useAltHashing;
        useAltHashing = sun.misc.VM.isBooted() &&
                (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
        boolean rehash = currentAltHashing ^ useAltHashing;

        table = newMap;
        //将旧数组中的数据依次添加到新table数组中
        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;
            }
        }
    }

put
添加键值对

 public synchronized V put(K key, V value) {
        //HashTable中不能插入value为null的元素 
        if (value == null) {
            throw new NullPointerException();
        }

        // 若HashTable中已存在键为key的键值对,则用新的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;
            }
        }
        //更改修改次数+1
        modCount++;
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();

            tab = table;
            hash = hash(key);
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        //将Hashtable中index位置的Entry(链表)保存到e中,将键值对插进entry链表中
        Entry<K,V> e = tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        //元素数量+1 
        count++;
        return null;
    }

remove
通过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;
    }


**clea**r
进行清空

 public synchronized void clear() {
        Entry tab[] = table;
        modCount++;
        for (int index = tab.length; --index >= 0; )
            tab[index] = null;
        count = 0;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值