HashMap主要方法

目录

hashMap(int)

putIfAbsent

resize()

getOrDefault

computeIfAbsent  

afterNodeAccess

computeIfPresent


hashMap(int)

过程:

hashMap初始化

public HashMap(int initialCapacity) {
    // 传入初始化大小和加载因子
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

校验和赋值

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;
        this.threshold = tableSizeFor(initialCapacity);
    }

关键的来了,返回指定大小最接近的2次幂数值

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

这边返回的是阈值threshold,达到这个值就会触发扩容,你传入的是多大就是多大的容量capacity,但是阈值会按照接近的2次幂值设定,我理解如果不传入指定的长度,默认按照16*0.75来设定阈值,如果你指定了就按照上面的进行设定

putIfAbsent

是这样,入参key和value,如果key在map中存在,返回key对应的value,不存在的话把key和value插入到map中,返回null

@Override
public V putIfAbsent(K key, V value) {
	return putVal(hash(key), key, value, true, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            // hashmap为空或者长度为0,扩容,获取长度
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            // 如果数组中该位置没有数据,直接设置头节点
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                // 如果放的位置就是有数据,创建节点
                e = p;
            else if (p instanceof TreeNode)
                // 好像是处理红黑树的吧
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            // 转化为红黑树
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    // 链表尾插法插数据
                    p = e;
                }
            }
            // e为空的话,就说明前面就没有找到key放的对应位置
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                // 这里面能找到,就返回e的值
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        // 找不到就返回null
        return null;	
    }

resize()

扩容hashMap

final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                // 长度为最大值,直接设定为最大值
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                // 容量翻倍,阈值翻倍
                newThr = oldThr << 1; // double threshold
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
            // 原map容量小于0,按阈值赋值容量
            newCap = oldThr;
        else {
            // 阈值为0,容量为0的情况,就按默认的来
            // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {
            // 数据复制过程
            old tab -> new tab
        }
        return newTab;
    }

getOrDefault

能从map中拿到数据,直接返回,否则返回给定值

public V getOrDefault(Object key, V defaultValue) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
}

computeIfAbsent  

这个和putIfAbsent区别就是,他这个可以通过lambda表达式进行计算出value值

如果 key 对应的 value 不存在,则使用获取 mappingFunction 重新计算后的值,并保存为该 key 的 value,否则返回 value。

public V computeIfAbsent(K key,
                         Function<? super K, ? extends V> mappingFunction) {
    if (mappingFunction == null)
        throw new NullPointerException();
    int hash = hash(key);
    Node<K,V>[] tab; Node<K,V> first; int n, i;
    int binCount = 0;
    TreeNode<K,V> t = null;
    Node<K,V> old = null;
    if (size > threshold || (tab = table) == null ||
        (n = tab.length) == 0)
        // 判断要不要扩容
        n = (tab = resize()).length;
    if ((first = tab[i = (n - 1) & hash]) != null) {
        // key找到对应位置后,不为空
        if (first instanceof TreeNode)
            // 是否为红黑树,我就不管了,看不懂
            old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
        else {
            // 不是红黑树,那就是链表了
            Node<K,V> e = first; K k;
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k)))) {
                    // 按照key值,去查找是否存在
                    // 找到赋值,然后赋值为旧值,break
                    old = e;
                    break;
                }
                ++binCount;// 每找一次,+1
            } while ((e = e.next) != null);
        }
        V oldValue;
        if (old != null && (oldValue = old.value) != null) {
            // 假如找到了这个值
            afterNodeAccess(old);
            return oldValue;
        }
    }
    // 没找到
    V v = mappingFunction.apply(key);
    if (v == null) {
        // lambda表达式是空,返回空
        return null;
    } else if (old != null) {
        old.value = v;
        afterNodeAccess(old);// 放到最后,然后返回
        return v;
    }
    //下面就是没有找到这个值
    else if (t != null) // 如果已经是红黑树的结构了,直接插入进去
        t.putTreeVal(this, tab, hash, key, v);
    else {
        // 那就是链表了,创建这个节点
        tab[i] = newNode(hash, key, v, first);
        if (binCount >= TREEIFY_THRESHOLD - 1)
            treeifyBin(tab, hash);
    }
    ++modCount;
    ++size;
    afterNodeInsertion(true);
    return v;
}

afterNodeAccess

这个节点放到最后

void afterNodeAccess(Node<K,V> e) { // move node to last
    LinkedHashMap.Entry<K,V> last;
    if (accessOrder && (last = tail) != e) {
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        p.after = null;
        if (b == null)
            head = a;
        else
            b.after = a;
        if (a != null)
            a.before = b;
        else
            last = b;
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
        tail = p;
        ++modCount;
    }
}

computeIfPresent

如果 key 对应的 value 不存在,则返回该 null,如果存在,则返回通过 remappingFunction 重新计算后的值。

public V computeIfPresent(K key,
                          BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    if (remappingFunction == null)
        throw new NullPointerException();
    Node<K,V> e; V oldValue;
    int hash = hash(key);
    if ((e = getNode(hash, key)) != null &&
        (oldValue = e.value) != null) {
        V v = remappingFunction.apply(key, oldValue);
        if (v != null) {
            // 存在则覆盖这个值
            e.value = v;
            afterNodeAccess(e);
            return v;
        }
        else
            // 我理解计算出来的值为null的话,就把这个key移除掉,验证了不存在移除掉
            removeNode(hash, key, null, false, true);
    }
    // 不存在则返回null
    return null;
}

示例

import java.util.HashMap;

class Main {
    public static void main(String[] args) {
        // 创建一个 HashMap
        HashMap<String, Integer> prices = new HashMap<>();

        // 往HashMap中添加映射关系
        prices.put("Shoes", 200);
        prices.put("Bag", 300);
        prices.put("Pant", 150);
        System.out.println("HashMap: " + prices);

        // 重新计算鞋加上10%的增值税后的价值
        int shoesPrice = prices.computeIfPresent("Shoes", (key, value) -> value + value * 10/100);
        System.out.println("Price of Shoes after VAT: " + shoesPrice);

        // 输出更新后的HashMap
        System.out.println("Updated HashMap: " + prices);
    }
}

执行以上程序输出结果为:

HashMap: {Pant=150, Bag=300, Shoes=200}
Price of Shoes after VAT: 220
Updated HashMap: {Pant=150, Bag=300, Shoes=220}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值