HashMap基本用法总结

文章目录

1.创建HashMap对象

HashMap<String, String> map = new HashMap<String, String>();

1.线程不安全的哈希表

2.键值对可以存储null,key不可以重复,value可以重复,重复时覆盖oldVlue

3.取出的数据没有顺序。

2.添加键值对

put方法添加元素时,如果key已经存在,则更新value的值。

存储的key和value都可以为null。

HashMap<String, String> map = new HashMap<String, String>();
map.put("北京", "key存在的oldValue");
map.put("上海", null);
map.put("广州", "oldValue");
map.put(null, "null的oldValue");
map.putIfAbsent(null, "null的newValue");
map.putIfAbsent("杭州", "key不存在的value");
map.putIfAbsent("北京", "key存在的newValue");
map.putIfAbsent("上海", "null值被覆盖");
map.replace("广州", "replaceValue");
map.replace("武汉", "key不存在的value");

replace(key,value);

当key存在时,调用replace方法,会替换value。当key不存在,返回null

@Override
public V replace(K key, V value) {
    Node<K,V> e;
    if ((e = getNode(hash(key), key)) != null) {
        V oldValue = e.value;
        e.value = value;
        afterNodeAccess(e);
        return oldValue;
    }
    return null;
}

putIfAbsent()当key存在,value有值时不会覆盖value值。

  1. 首先判断key是否存在,不存在和put的作用一致,更新value。
  2. 如果存在判断value是否为null,value为null,则更新value值。
  3. value不为null,则不覆盖,返回原来的value。(null和不存在是两个概念)

put方法源码:

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

put方法return的参数中第三个为false。

putIfAbsent源码:

@Override
public V putIfAbsent(K key, V value) {
    return putVal(hash(key), key, value, true, true);
}

注意这里return的参数中第三个是true。这个参数的定义有注释说明:

@param onlyIfAbsent if true, don’t change existing value。如果为true,不改变已经存在的value值。

进入到putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict):

/**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
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)
            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;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                //如果传入的参数onlyIfAbsent为true或者oldvalue是null,更新value。
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

3.获取元素

1.get(key)获取HashMap的value

String valueStr=map.get("北京");

2.遍历map.keySet获取HashMap的key

1.ForEach迭代key

 for (String key : map.keySet()) {
 	System.out.println("key= "+ key + ":" + map.get(key));
 }

2.Iterator遍历key

Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
    String key = (String) iterator.next();
    System.out.println(key + ":" + map.get(key));
}

Console:

null:null的oldValue

上海:null值被覆盖

广州:replaceValue

杭州:key不存在的value

北京:key存在的oldValue

3.遍历map.value获取HashMap的value

1.ForEach迭代value

for (String v : map.values()) {
	System.out.println("value= " + v);
}

2.Iterator遍历value

Iterator<String> iterator1 = map.values().iterator();
while (iterator1.hasNext()) {
	String value = (String) iterator1.next();
    System.out.println("value:" + value);
}

Console:

value= null的oldValue

value= null值被覆盖

value= replaceValue

value= key不存在的value

value= key存在的oldValue

4.遍历Map.entry获取HashMap的key,value

1.ForEach迭代遍历

for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}

2.Iterator遍历

Iterator<Entry<String, String>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Entry<String, String> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

Console:

null:null的oldValue //key为null,但是是存在的,所以未覆盖

上海:null值被覆盖 //key存在,且value为null,更新oldValue

广州:replaceValue

杭州:key不存在的value //key不存在,更新value

北京:key存在的oldValue //key存在,value不为null,则不更新value

5.通过JDK1.8 Lambda表达式遍历

map.forEach((k, v) -> {
    System.out.println("key:" + k + "\tvalue:" + v);
});

Cosole:

key:null value:null的oldValue

key:上海 value:null值被覆盖

key:广州 value:replaceValue

key:杭州 value:key不存在的value

key:北京 value:key存在的oldValue

通过输出可以看到输出的数据与输入的数据顺序不一致,证明hashmap是无序的,实际上hash进行离散,得到的数据就不会按照大小进行排序。有序的map可以使用treeMap等。

4.判断key或value是否存在

// 判断map是否含有key
boolean ifContainKey = map.containsKey("杭州");
System.out.println("ifContainkey:"+ifContainKey);
// 判断map是否含有value
boolean ifContainValue = map.containsValue(null);
System.out.println("ifContainValue:"+ifContainValue);

Console:

ifContainkey:true

ifContainValue:true

5.删除元素

remove(key);存在key返回对应的value,否则返回null

remove(key,value);存在key-value,返回true。否则返回false

String value = map.remove("上海");
System.out.println(value);
String value2 = map.remove("das");
System.out.println(value2);
boolean flag = map.remove("北京", "key存在的oldValue");
System.out.println(flag);
boolean flag2 = map.remove("武汉", "key存在的oldValue");
System.out.println(flag2);

Console:

null值被覆盖

null

true

false

上一篇:Sword 内存屏障-Store Buffer


下一篇:ARM64体系结构与编程之cache必修课(下)