HashMap基本用法

上参考链接:https://blog.csdn.net/weixin_43263961/article/details/86427533

Part1:put, remove, containsKey, containsValue;

HashMap<String, String> map = new HashMap<>();
    map.put("1", "a");
    map.put("2", "b");
    map.put("3", "a");
    map.put("4", "c");
    //map.put("4", "d");  //可以运行键值都为"4"(如果键相同,后者覆盖前者)
    System.out.println(map);
    System.out.print(map.keySet()+" ");  //集合中所有键以Set集合形式返回
    System.out.println();
    System.out.print(map.values()+" ");  //集合中所有值以Collection集合形式返回
    System.out.println();
    System.out.println("集合大小:"+map.size());
    System.out.println("是否包含该键:"+map.containsKey("2"));  //返回boolean
    System.out.println("是否包含该值:"+map.containsValue("b"));  //返回boolean
    System.out.println(map.isEmpty());  //判断是否为空,若不包含键-值映射关系则返回true
    map.remove("4");  //删除映射关系
    System.out.println(map);
    map.clear();//清空集合
    System.out.println(map);

public V put(K key, V value) 方法源代码解析

public V put(K key, V value)   
{   
 // 如果 key 为 null,调用 putForNullKey 方法进行处理  
 if (key == null)   
     return putForNullKey(value);   
 // 根据 key 的 keyCode 计算 Hash 值  
 int hash = hash(key.hashCode());   
 // 搜索指定 hash 值在对应 table 中的索引  
     int i = indexFor(hash, table.length);  
 // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素  
 for (Entry<K,V> e = table[i]; e != null; e = e.next)   
 {   
     Object k;   
     // 找到指定 key 与需要放入的 key 相等(hash 值相同  
     // 通过 equals 比较放回 true)  
     if (e.hash == hash && ((k = e.key) == key || key.equals(k)))   
     {   
         V oldValue = e.value;   
         e.value = value;   
         e.recordAccess(this);   
         return oldValue;   
     }   
 }   
 // 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry   
 modCount++;   
 // 将 key、value 添加到 i 索引处  
 addEntry(hash, key, value, i);   
 return null;   
}   

关于代码中的 entry.recordAccess(this)函数:
这是考虑到LinkedHashMap(链表形式的HashMap)的特性:
Linked内部含有一个private transient Entry header;来记录元素插入的顺序或者是元素被访问的顺序。利用这个线性结构的对象,可以帮助记录entry加入的前后顺序或者记录entry被访问的频率(最少被访问的entry靠前,最近访问的entry靠后)。大致的过程如下:
new LinkedHashMap(10, 0.75, true);
其中前面两个参数就是HashMap构造函数需要的参数,后面的true表明LinkedHashMap按照访问的次序来排序。
按照访问的次序来排序的含义:当调用LinkedHashMap的get(key)或者put(key, value)时,碰巧key在map中被包含,那么LinkedHashMap会将key对象的entry放在线性结构的最后。
按照插入顺序来排序的含义:调用get(key), 或者put(key, value)并不会对线性结构产生任何的影响。

void recordAccess(HashMap m) {
            LinkedHashMap lm = (LinkedHashMap)m;
            if (lm.accessOrder) {
                lm.modCount++;
               remove();
                addBefore(lm.header); //将该entry放在header线性表的最后
            }
        }

正是因为LinkedHashMap提供按照访问的次序来排序的功能,所以它才需要改写HashMap的get(key)方法(HashMap不需要排序)和HashMap.Entry的recordAccess(HashMap)方法。总之:如果有对于Map中元素位置依据插入/查找顺序排列的需求,覆写HashMap中的recordAccess方法!
至于初始化!!江湖传说还有这样一种初始化方法,比上面的简洁一丢丢:

HashMap<String, String> map = new HashMap<String, String>() {
    {
        map.put("name", "test");  
        map.put("age", "20"); 
    }
};

第一层括弧实际是定义了一个匿名内部类 (Anonymous Inner Class),第二层括弧实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。推而广之,可初始化ArrayList、Set等其他集合类。然而当我把HashMap定义成类的成员变量,在定义处使用给这个初始化块,会报NullPointer错,后面再把这个问题深入研究一下。

Part2:存取值

get (取key对应的Value)

map.put("DEMO", 1);
/*Value的类型*///得到map中key相对应的value的值
System.out.println(map.get("DEMO"));//1
System.out.println(map.get("1"));//null 需要自己实现、取Value对应的Key的方法

取Value对应的Key

第一种方法:map.keySet()

(1) For-Each

public static Object getKey(HashMap map, Object value){
        ArrayList<Object> keyList = new ArrayList<>();
        for(Object key: map.keySet()){
            if(map.get(key).equals(value)){
                keyList.add(key);
            }
        }
        return keyList;
    }

(2) 迭代器

public static Object getKey(HashMap map, Object value){
        ArrayList<Object> keyList = new ArrayList<>();
        Set <Object> keys = map.keySet();
        Iterator<Object> it = keys.iterator();
        Object key;
        while (it.hasNext()) {
            key = it.next();
            if(map.get(key).equals(value)){
                keyList.add(key);
            }
        }
        return keyList;
    }

第二种方法:map.entrySet()

(1) For-Each

public static Object getKey(HashMap map, Object value){
        ArrayList<Object> keyList = new ArrayList<>();
        Set<Entry<Object, Object>> entrySet = map.entrySet();
        for (Entry<Object,Object> entry:entrySet) {
            if(entry.getValue().equals(value)){
                keyList.add(entry.getKey());
            }
        }
        return keyList;
    }

(2) 迭代器

public static Object getKey(HashMap map, Object value){
        ArrayList<Object> keyList = new ArrayList<>();
        Set<Entry<Object, Object>> entrySet = map.entrySet();
        Iterator<Entry<Object, Object>> it = entrySet.iterator();
        Entry<Object, Object> entry;
        while(it.hasNext()){          
            entry = it.next();
            if(entry.getValue().equals(value)){
                keyList.add(entry.getKey());
            }
        }
        return keyList;
    }

Part3:遍历

第一种方法:使用keySet()

这种方法遍历了2次,一次是转为iterator,另一次是从HashMap中取出key所对应的value。

(1) For-Each

Set<String> keys = map.keyset();
for(String key: keys){
    System,out.println(key+":"+map.get(key));
}

(2) 迭代器

Set<String> keys = may.keyset();
Iterator<String> IT= keys.iterator();
String key;
while(it.hasNext()){
    key = it.next();
    System,out.pritln(key+":"+map.get(key));
}

第二种方法:使用entrySet()

首先先来说一下Entry,由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。
Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value (我们总说键值对键值对, 每一个键值对也就是一个Entry)
Map.Entry里面包含getKey()和getValue()方法。
大部分时候,对于Map的遍历我们都是借助于Entry来做的。

Iterator<Map.Entry<Integer, Integer>> it=map.entrySet().iterator(); //建立一个entry对象的的迭代器
    while(it.hasNext()) {
        Map.Entry<Integer,Integer> entry=it.next();
        int key=entry.getKey();
        int value=entry.getValue();
        System.out.println(key+" "+value);
    }

这种方法只遍历了1次,它把key和value都放到了entry中,因此比keySet()快。

(1) For-Each(普遍选它)

    Set<Entry<String,String>> entrySet = map.entrySet();  //map.entrySet()返回<key,value>键值对的集合
    for (Entry<String,String> entry:entrySet) {
        System.out.println(entry.getKey()+":"+entry.getValue());  //entry.getKey()返回key,entry.getValue()返回value
    }

(2) 迭代器

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

总结:当map中容量较大时,推荐使用第二种entrySet()的方法。

part4

(1)根据key值将map排序

(1)根据value值将map排序

深入理解HashMap