JavaSE Map接口(HashMap、LinkedHashMap、HashTable、Properties、TreeMap)

Java自我学习路线

一、Map

1. Map接口概述

  • Map集合与Collection集合没有关系,在Map集合中不能直接使用Iterator接口遍历元素
  • key和value都是存储Java对象的内存地址
  • Map是具有映射关系的集合,以key-value键值对的方式存储元素,其中key起决定性作用,所有Map集合的key都是无序不可重复的(和Set集合存储元素特点相同)
  • key与value是一一对应的,可以通过key来获取value,且key只能映射到一个value,另外不能存在相同的key,但value可以相同
  • Map集合的数据结构针对键有效,跟值无关;Collection集合的数据结构针对元素有效
  • 当访问的值不存在的时候,方法就会抛出一个 NoSuchElementException 异常
  • 当对象的类型和 Map 里元素类型不兼容的时候,就会抛出一个 ClassCastException 异常
  • 当在不允许使用 Null 对象的 Map 中使用 Null 对象,会抛出一个 NullPointerException 异常
  • 当尝试修改一个只读的 Map 时,会抛出一个 UnsupportedOperationException 异常
  • 在Map中存储的每一个键值对都是以一个Map.Entry<K,V>的实现对象存储的,Map.Entry是一个接口,不能实例化,所以Map的不同实现类,存储键值对的方式也会有所不同,只要这个键值对的类实现了Map.Entry接口即可

2. Map接口常用方法

2.1 put方法

  • 向Map集合中添加键值对
V put(K key, V value);
2.1.1 put 实现原理
  • map.put(k,v)实现原理
    先将k,v封装到Node对象当中,然后底层调用k的hashCode()方法得出哈希值,接着通过哈希算法(函数),将哈希值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上,如果说下标对应的位置上有链表,此时会拿着k和链表上的每一个节点中的k进行equals()比较,如果所有的equals()方法返回的都是false,那么这个新节点将被添加到链表的末尾,如果其中有一个equals()返回了true,那么这个节点的value将会被覆盖
  • 调用两个方法,先调用hashCode(),再调用equals(),所以这两个方法需要重写
  • 同一个单向链表上所有节点的哈希值相同,因为其数组下标是一样的,但同一个链表上k和k的equals()方法一定返回false
  • put源码:
public V put(K key, V value)   
{
      
 // 如果 key 为 null,调用 putForNullKey 方法进行处理  
 if (key == null)   
     return putForNullKey(value);   
 // 根据 key 的 hashCode() 计算 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;   
}  

2.2 get方法

  • 通过key获取value
V get(Object key);
2.2.2 get 实现原理
  • v = map.get(k)实现原理
    先调用k的hashCode()方法得出哈希值,通过哈希算法(函数)将哈希值转换成数组的下标,通过数组的下标快速定位到某个位置上,如果这个位置上什么也没有,则返回null,如果这个位置上有单向链表,那么会拿着参数k和单向链表上的每一个节点中的k进行equals()比较,如果所有equals()方法返回false,那么get方法返回null,只要其中有一个节点的k和参数k在equals()比较时返回true,那么此时这个节点的value就是所要得到的value,get方法返回此value
  • 调用两个方法,先调用hashCode(),再调用equals(),所以这两个方法需要重写
  • get源码:
public V get(Object key)   
{
      
 // 如果 key 是 null,调用 getForNullKey 取出对应的 value
 if (key == null)   
     return getForNullKey();   
 // 根据该 key 的 hashCode() 计算它的哈希值
 int hash = hash(key.hashCode());   
 // 直接取出 table 数组中指定索引处的值
 for (Entry<K,V> e = table[indexFor(hash, table.length)];   
     e != null;   
     // 搜索该 Entry 链的下一个 Entr
     e = e.next)
 {
      
     Object k;   
     // 如果该 Entry 的 key 与被搜索 key 相同
     if (e.hash == hash && ((k = e.key) == key
         || key.equals(k)))
         return e.value;
 }   
 return null;   
}   

2.3 clear方法

  • 清空Map集合
void clear();

2.4 containsKey方法

  • 判断Map中是否包含某个key
boolean containsKey(Object key);

2.5 containsValue方法

  • 判断Map中是否包含某个value
boolean containsValue(Object value);

2.6 isEmpty方法

  • 判断Map集合中元素个数是否为0
boolean isEmpty();

2.7 remove方法

  • 通过key删除键值对
V remove(Object key);

2.8 size方法

  • 获取Map集合中键值对的个数
int size();

2.9 values方法

  • 获取Map集合中所有的value,返回一个Collection
Collection<V> values();

2.10 keySet方法

  • 获取Map集合所有的key(所有的key是一个set集合)
Set<K> keySet();

2.11 entrySet方法

  • 将Map集合转换成Set集合,此集合的类型为Map.Entry
Set<Map.Entry<K, V>> entrySet();
  • Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>,它表示的是Map中的一个实体(key-value),接口中常用方法有getKey(),getValue等方法
interface Entry<K,V> {
   
    K getKey();

    V getValue();

    V setValue(V value);

    boolean equals(Object o);

    int hashCode();    

    // 返回一个Comparator<Map.Entry<K,V>> 是用来比较Entry的Key1.compareTo(Key2)
    // 这个Comparator是Serializable的;这里用到了&强转
    // key实现了Comparable
    public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
   
        return (Comparator<Map.Entry<K, V>> & Serializable)
            (c1, c2) -> c1.getKey().compareTo(c2.getKey());
    }    

    // 与上一个方法类似,只不过比较的是Entry中的value的值
    public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
   
        return (Comparator<Map.Entry<K, V>> & Serializable)
            (c1, c2) -> c1.getValue().compareTo(c2.getValue());
    }    

    // 用自定义的Comparator方法来创建一个比较Map.Entry<K,V>中的Key的Comparator对象
    // 且这个自定义的Comparator对象里比较的参数的类型是Map.Entry<K,V>中K的相同类型或者父类
    public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
   
        Objects.requireNonNull(cmp);
        return (Comparator<Map.Entry<K, V>> & Serializable)
            (c1, c2) -> cmp.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jayco-J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值