集合---Map

一,HashTable

哈希表,它相比于hashMap结构简单点,它没有涉及红黑树,直接使用链表的方式解决哈希冲突。

我们看它的字段,和hashMap差不多,使用table存放元素

private transient Entry<?,?>[] table;
private transient int count;  //entry 节点数量
private int threshold;    //rehash 刷新的 阈值
private float loadFactor;    //负载因子
private transient int modCount = 0;     

节点Entry:

private static class Entry<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Entry<K,V> next;

注意这个结构,数组+链表

它没有常量字段,默认值是在构造方法里面直接体现的,我们看一下无参构造:

public Hashtable() {
    this(11, 0.75f);
}
public Hashtable(int initialCapacity, float loadFactor) {
    if (initialCapacity==0)
        initialCapacity = 1;
    this.loadFactor = loadFactor;  //负载因子
    table = new Entry<?,?>[initialCapacity]; //初始化大小
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}

1.get()方法

根据key,计算hash值,获得Index,通过数组的随机访问,直接获得entry节点,再变量entry链表,比较hash和key都相同的entry,获取内部的value值。

public synchronized V get(Object key) {
    Entry<?,?> tab[] = table;
//计算下标
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
//遍历查找,e=e.next
    for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
        if ((e.hash == hash) && e.key.equals(key)) {
            return (V)e.value;
        }
    }
    return null;
}

2.put()方法

与get()方法类似,也是遍历table,然后调用addEntry()实现添加。

public synchronized V put(K key, V value) {
    if (value == null) {
        throw new NullPointerException();
    }
    Entry<?,?> tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[index];
//如果已经存在,则覆盖,返回老的值
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            V old = entry.value;
            entry.value = value;
            return old;
        }
    }
//不存在,直接添加
    addEntry(hash, key, value, index);
    return null;
}

addEntry()

private void addEntry(int hash, K key, V value, int index) {
    modCount++;
    Entry<?,?> tab[] = table;
    if (count >= threshold) {    //大小超过阈值,要扩容
        // Rehash the table if the threshold is exceeded
        rehash();
        tab = table;
        hash = key.hashCode();
        index = (hash & 0x7FFFFFFF) % tab.length;
    }
//添加
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>) tab[index];
    tab[index] = new Entry<>(hash, key, value, e); //放到链表头部
    count++;
}

扩容: 直接 OldCapacity*2+1,然后将存在的entry重新计算hash值,导入新容器中。

注意这里的手法,直接将新来的节点,放到头部,这样就可以不管后面是否存在节点,都不会出现问题

protected Entry(int hash, K key, V value, Entry<K,V> next) {
    this.hash = hash;
    this.key =  key;
    this.value = value;
    this.next = next;
}

 

二,TreeMap

TreeMap和之前的两个map就不同了,它没有使用哈希表,而是直接使用红黑树解决,它的字段只保存了根节点。

 注意:之所以说treeMap是有序的,是因为treemap在插入的时候,比较的是key的值,而hashTable和HashMap比较的只是key的hash值,所以产生了不同。因为hash值要用来构建数组,进行映射,无法达到有序的状态,而TreeMap不需要数组,根节点直接就是树状,所以能够达到有序!

private final Comparator<? super K> comparator; //排序比较器
private transient Entry<K,V> root;    //根节点
private transient int size = 0;
private transient int modCount = 0;

entry节点:

static final class Entry<K,V> implements Map.Entry<K,V> {
    K key;
    V value;
    Entry<K,V> left;
    Entry<K,V> right;
    Entry<K,V> parent;
    boolean color = BLACK;

1.get()

public V get(Object key) {
    Entry<K,V> p = getEntry(key);
    return (p==null ? null : p.value);
}

getEntry()

final Entry<K,V> getEntry(Object key) {
    // Offload comparator-based version for sake of performance
    if (comparator != null)
        return getEntryUsingComparator(key);
    if (key == null)
        throw new NullPointerException();
    @SuppressWarnings("unchecked")
        Comparable<? super K> k = (Comparable<? super K>) key;
    Entry<K,V> p = root;
    while (p != null) {
        int cmp = k.compareTo(p.key);
        //左右分流
        if (cmp < 0)
            p = p.left;
        else if (cmp > 0)
            p = p.right;
        else
            return p;
    }
    return null;
}

2.put() 涉及红黑树的操作,所以代码比较长

public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key); // type (and possibly null) check

        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry<K,V> parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

3.remove()

public V remove(Object key) {
    Entry<K,V> p = getEntry(key);
    if (p == null)
        return null;

    V oldValue = p.value;
    deleteEntry(p);  //实际方法
    return oldValue;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值