Map接口和常用方法

在这里插入图片描述
Map是什么
  Java中的map是一种键-值对(key-value)集合(容器)Map 集合中的每一个元素都包含一个键对象和一个值对象。其中,键对象不允许重复,而值对象可以重复,并且值对象还可以是 Map 类型的,就像数组中的元素还可以是数组一样。

  Map 接口主要有两个实现类:HashMap 类和 TreeMap 类。其中,HashMap 类按哈希算法来存取键对象,而 TreeMap 类可以对键对象进行排序。

Map的特点
Map :
  键值对的集合| 映射的集合
  键值对的key的唯一的,去重的,无序的 — > Set
  键值对的value,可重复,无序的 — > Collection
  一个key只能对应一个value
  去重 : key相同value覆盖

Map 接口中提供的常用方法如下:

方法名作用
V get(Object key)返回 Map 集合中指定键对象所对应的值。V 表示值的数据类型
V put(K key, V value)向 Map 集合中添加键-值对,返回 key 以前对应的 value,如果没有, 则返回 null
V remove(Object key)从 Map 集合中删除 key 对应的键-值对,返回 key 对应的 value,如果没有,则返回null
Set entrySet()返回 Map 集合中所有键-值对的 Set 集合,此 Set 集合中元素的数据类型为 Map.Entry
返回 Map 集合中所有键-值对的 Set 集合,此 Set 集合中元素的数据类型为 Map.Entry返回 Map 集合中所有键对象的 Set 集合

Map 遍历方式 :

  1. Collection values() 返回此映射中包含的值的Collection视图。
  2. Set keySet() 返回此映射中包含的键的Set视图。
  3. Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图。
System.out.println("----------------values()----------------");
Collection<String> values = map.values();
for(String str:values){
	System.out.println(str);
}

System.out.println("-------------keySet()-----------------");
Set<Integer> keys =  map.keySet();
Iterator<Integer> it = keys.iterator();
while(it.hasNext()){
    Integer key = it.next();
    String value = map.get(key);
    System.out.println(key+"--->"+value);
}

System.out.println("-------------entrySet()-----------------");
Set<Map.Entry<Integer,String>> entrys = map.entrySet();
for (Map.Entry<Integer,String> entry:entrys){
    System.out.println(entry.getKey());
    System.out.println(entry.getValue());
}

TreeMap

TreeMap :
  存储键值对数据,key是唯一的,去重的,无序的(存放的顺序与内部真实存储的顺序不保证一致)

  • ​ 底层结构 : 红黑树

  • ​ 特点 : 根据key做自动升序排序(比较器)

  • ​ 去重与升序排序 : 根据key比较规则做去重与排序

  • ​ 新增方法 : 新增了一些与比较大小相关的方法

注意 : Map集合下所有的实现类,去重|排序都是根据key实现的,与value无关存储键值对数据,key是唯一的,去重的,无序的(存放的顺序与内部真实存储的顺序不保证一致)

匿名内部类

TreeMap<Person,Double> map = new TreeMap<>(new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
    	return o1.getAge()-o2.getAge();
    }
});

lambda

TreeMap<Person,Double> map = new TreeMap<>((o1, o2)->{
	return o1.getAge()-o2.getAge();
});

HashMap :
  基于哈希表的Map接口的实现。 此实现提供了所有可选的映射操作,并允许null值和null键。

  • 底层结构 : 哈希表(jdk8之前:数组+链表 jdk8及之后:数组+链表+红黑树)
  • 特点 : 查询增删效率高,去重根据键值对的key实现
  • 应用场景 : 适合应用在存储多个键值对数据的情况下,查询增删效率高应用场景
  • 新增方法 : 无新增方法
  • 遍历方式 : 1)values() 2)keySet() 3)entrySet()

初始容量 :默认static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; --> 可以通过构造器指定
加载因子 : 默认static final float DEFAULT_LOAD_FACTOR = 0.75f; --> 可以通过构造器指定
扩容阈值 : threshold 存储数据的个数size > 数组的容量*加载因子
扩容机制 : 每次扩容原容量的2倍 newCap = oldCap << 1
哈希表中存储键值对的个数 : size

hashmap存储过程
存储过程 :

  1. 调用put方法添加键值对key,value数据

  2. 根据key计算hash值
    int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

  3. 调用putVal(hash,key,value)实现存储键值对数据

  4. 执行putVal方法,第一步就判断哈希表底层的节点数组是否==null,或者底层数组的长度==0,如果是证明这是第一次添加,底层没有数组或者没有带有容量的数组,先调用resize()方法实现创建新数组

    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    
  5. 根据key的hash值计算位桶索引int index = (n - 1) & hash,判断table[index]==null是否存在单向链表的首节点
    if ((p = tab[i = (n - 1) & hash]) == null)

  6. 如果=null,证明不存在单向链表,直接创建新节点,存储这一次要添加的键值对数据,直接放在数组table[index]作为单向链表的首节点
    tab[i] = newNode(hash, key, value, null); --> new Node<>(hash, key, value, next)

  7. 如果!=null,证明存在单向链表的首节点,遍历这个链表,判断链表中每一个节点的存储的key与这一次要添加的键值对的key比较是否相等, if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))

    如果相同value覆盖
    V oldValue = e.value;
    e.value = value;
    return oldValue;
    如果不相同创建新节点,挂在原单向链表的最后
    p.next = newNode(hash, key, value, null);

  8. 如果以上的步骤中执行到了new Node()创建新节点放入哈希表中,数据个数+1,判断是否>扩容阈值threshold,如果满足,就调用resize方法实现扩容
    ​ if (++size > threshold)
    ​ resize();

注意 :
  哈希表底层节点数组的长度为2的整数次幂
  当单向链表的节点个数>=8(static final int TREEIFY_THRESHOLD = 8;),并且同时哈希表的节点数组的容量>=64(static final int MIN_TREEIFY_CAPACITY = 64;),就把单向链表优化成红黑树
  但是如果数组的容量<64,就调用resize()实现数组的扩容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值