Map

时间:2024-10-22 08:14:46

概述

双列集合:用来存储键值对的集合。

  • interface Map<K,V> : K(key)键 ,V(value)值
  • 将键映射到值的对象,不能出现重复的键,每个键最多可以映射到一个值

1、Map和Collection没有继承关系。
2、Map集合以key和value的方式存储数据:键值对
key和value都是引用数据类型。
key和value都是存储对象的内存地址。
key起到主导的地位,value是key的一个附属品。

Map的基本方法

方法名 说明
V put(K key,V value) 设置键值对
V remove(Object key) 删除元素
void clear() 清空集合
boolean containsKey(Object key) 判断键是否存在,存在则返回true
boolean containsValue(Object value) 判断值是否存在,存在则返回true
boolean isEmpty() 判断集合是否为空
int size() 获取集合元素个数
import java.util.HashMap;
import java.util.Map;
 
public class Map01 {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
 
        map.put("STU001","Andy");
        map.put("STU002","Jack");
        map.put("STU003","Tom");
        map.put("STU004","Bob");
        map.put("STU004","Smith");//设置(修改)
        //如果键不存在,则表示添加元素。如果键存在,则表示设置值。
 
        //删除
        System.out.println(map.remove("STU003"));  //Tom
        //判断是否包含
        System.out.println(map.containsKey("STU003"));  //false
        System.out.println(map.containsKey("STU004"));  //true
        System.out.println("-----------------------");
        System.out.println(map.containsValue("Tom"));  //false
        System.out.println(map.containsValue("Smith")); //true
 
        System.out.println("-----------------------");
        System.out.println(map.isEmpty());//判断集合是否为空   false
        map.clear();//清空集合
        System.out.println(map.isEmpty()); //true
 
        System.out.println(map); //{}
 
    }
}

Map集合的获取功能

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
 
public class map_get {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
 
        map.put("STU001","Andy");
        map.put("STU002","Jack");
        map.put("STU003","Tom");
        map.put("STU004","Bob");
 
        //get通过键获取值
        System.out.println(map.get("STU003"));
        System.out.println("------------------");
        //keySet 获取所有键的Set集合
        Set<String> keySet = map.keySet();
        System.out.println(keySet);
        //values  获取所有值的Collection集合
        Collection<String> values = map.values();
        System.out.println(values);
        //entrySet  获取所有键值对对象的Set集合
        Set<Map.Entry<String, String>> es = map.entrySet();
        //Map集合通过entrySet()方法转换成的这个Set集合,Set集合中元素的类型是 Map.Entry<K,V>
        //Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态内部类
        System.out.println(es);
         //[STU001=Andy, STU003=Tom, STU002=Jack, STU004=Bob]
         for (Map.Entry<String, String> entry:es){
             System.out.println("key:"+entry.getKey()+"    "+"value:"+entry.getValue());
         }
        /*
        key:STU001    value:Andy
        key:STU003    value:Tom
        key:STU002    value:Jack
        key:STU004    value:Bob
         */
    }
}

哈希表

通过 数组 + 链表 实现的一种数据结构

哈希表的构造方法的参数是一个长度为16个元素的数组,通过哈希值 % 16 的值,作为头节点在数组中选择对应的位置,就形成了哈希表。

HashMap

底层源码

 public class HashMap{
            // HashMap底层实际上就是一个数组。(一维数组)
            Node<K,V>[] table;
            // 静态的内部类HashMap.Node
            static class Node<K,V> {
                final int hash; // 哈希值(哈希值是key的hashCode()方法的执行结果。hash值通过哈希函数/算法,可以转换存储成数组的下标。)
                final K key; // 存储到Map集合中的那个key
                V value; // 存储到Map集合中的那个value
                Node<K,V> next; // 下一个节点的内存地址。
            }
        }

特点

  • 1、无序,不可重复。
    为什么无序? 因为不一定挂到哪个单向链表上。
    不可重复是怎么保证的? equals方法来保证HashMap集合的key不可重复。
    如果key重复了,value会覆盖。

  • 2、放在HashMap集合key部分的元素其实就是放到HashSet集合中了。
    所以HashSet集合中的元素也需要同时重写hashCode()+equals()方法。

  • 3、HashMap集合的默认初始化容量是16,默认加载因子是0.75
    这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组以二叉树开始扩容。

重点,记住:HashMap集合初始化容量必须是2的倍数,这也是官方推荐的,
这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的。

注意

1.向Map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,然后再调用equals方法! equals方法有可能调用,也有可能不调用。 拿put(k,v)举例,什么时候equals不会调用?
k.hashCode()方法返回哈希值, 哈希值经过哈希算法转换成数组下标。 数组下标位置上如果是null,equals不需要执行。 拿get(k)举例,什么时候equals不会调用? k.hashCode()方法返回哈希值, 哈希值经过哈希算法转换成数组下标。 数组下标位置上如果是null,equals不需要执行。
4.假设将所有的hashCode()方法返回值固定为某个值,那么会导致底层哈希表变成了 纯单向链表。
这种情况我们成为:散列分布不均匀。什么是散列分布均匀?

假设有100个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的, 是散列分布均匀的。假设将所有的hashCode()方法返回值都设定为不一样的值,可以吗,有什么问题? 不行,因为这样的话导致底层哈希表就成为一维数组了,没有链表的概念了。 也是散列分布不均匀。散列分布均匀需要你重写hashCode()方法时有一定的技巧。