java中的Map接口及实现类

Map接口

MapMUL图

1、Map接口基本情况

  • Map用于保存具有映射关系的数据(Set集合也有这样的特点,只不过value的值是规定好的)

  • Map中的key和value可以是任意数据类型的,会封装到HashMap$Node对象中;

  • Map中的key是不允许重复的,原因和HashSet一样

  • Map 中存入相同的key值元素,会产生替换的效果,将原来的key值得数据进行替换

    Map map = new HashMap();
    map.put("001","jack");
    map.put("002","tom");
    map.put("001","jerry");
    System.out.println(map);
    //  {001=jerry, 002=tom}
    
  • Map中的value是可以重复的,

  • Map中key可以为null,value也可以为null,注意key为null的只有一个,value可以有多个null值

  • 常用String作为Map中的key其他类型可以,因为他是Object类型的

  • key 和value直接存在单一对应关系,既可以通过key值总能找到对应的value值

  • map接口中的常用方法:

    1. put(); 添加
    2. remove方法:
    3. get()
    4. isEmpty
    5. size()
    6. clear()
    7. containsKey()

2、遍历方式:

1、先取出所有的key,在通过key取出对应的value

  • 增强for循环

    Map map = new HashMap();
    map.put("122",12);
    map.put("123",13);
    map.put("124",14);
    Set set = map.keySet();
    for(Object item : set){
     	sout(item + "-" + map.get(item));
    }
    
  • 迭代器

    Map map = new HashMap();
    map.put("122",12);
    map.put("123",13);
    map.put("124",14);
    Set set = map.keySet();
    Iterator iterator = set.iterator();
    while (iterator.hasNext()) {
    	Object key =  iterator.next();
    	System.out.println(key + "-" + map.get(key));
    }
    

2、将所有的value值取出

  • 增强for

    Map map = new HashMap();
    map.put("122",12);
    map.put("123",13);
    map.put("124",14);
    
    Collection values = map.values();
    for (Object item : values) {
    System.out.println(item);
    }
    
  • 迭代器

    Map map = new HashMap();
    map.put("122",12);
    map.put("123",13);
    map.put("124",14);
    
    Collection values = map.values();
    
    Iterator iterator = values.iterator();
    while (iterator.hasNext()) {
    Object next =  iterator.next();
    System.out.println(next);
    }
    

3、通过entrySet方法获取获取一个类型为Map.Entry的集合

  • 增强for

    Map map = new HashMap();
    map.put("122",12);
    map.put("123",13);
    map.put("124",14);
    
    Set set = map.entrySet();
    for (Object entry : set) {
    Map.Entry item = (Map.Entry) entry;
    System.out.println(item.getKey() + " " + item.getValue());
    }
    
  • 迭代器

    Map map = new HashMap();
    map.put("122",12);
    map.put("123",13);
    map.put("124",14);
    
    Set set = map.entrySet();
    
    Iterator iterator = set.iterator();
    while (iterator.hasNext()) {
        Map.Entry entry =  (Map.Entry) iterator.next();
        System.out.println(entry.getKey() + " " + entry.getValue());
    }
    

3、HashMap集合

扩容机制

  • HashMap底层维护了一个Node类型的数组table,默认为null

  • 当创建对象时,加载因子初始化为0.75,

  • 当添加key -value时,通过key的哈希值,得到在table中的索引然后判断该索引处是否有元素,如果没有元素直接添加,如果该索引处有元素,继续判断元素元素的key和准备加入的key值是否相等,则直接替换为value,如果不同需要判断是树结构还是链表结构,做出相应的处理,如果添加是发现容量不够,则需要扩容

  • 第一次添加,需要table容量为16,临界值为12,(16 * 0.75)

  • 以后再次扩容是,按照原来的两倍(32),临界值为(32 * 0.75) = 24;

  • 在java8 中如果一条链表的元素超过8个,并且table的大小,大于等于64,就会进行树化(红黑树)

  • 代码解读

     /*
            * 代码解读
            *
            * 1、执行构造方法: new HashMap();
            *    初始化加载因子 this.loadFactor = DEFAULT_LOAD_FACTOR; (0.75)
            *    HashMap$Node[] table = null;
            *
            * 2、执行put  (调用hash方法,计算key的值    hash值(return (key == null) ? 0 : (h =                       *key.hashCode()) ^ (h >>> 16);))
            *  public V put(K key, V value) {
            *        return putVal(hash(key), key, value, false, true);
            *   }
            *
            * 3、执行putval方法(最核心代码)
            *
            *   final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                                   boolean evict) {
                        Node<K,V>[] tab; Node<K,V> p; int n, i;
                        //判断table为null 或者size为0 是扩容为16;
                        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;
                                if (!onlyIfAbsent || oldValue == null)
                                    e.value = value;
                                afterNodeAccess(e);
                                return oldValue;
                            }
                        }
                        ++modCount;
                        if (++size > threshold)
                            resize();
                        afterNodeInsertion(evict);
                        return null;
                    }
    
            *
            * 会存在减枝的操作
            *  */
    

    注意:

    • 扩容是(开始为16),如果在某一条链上的个数等于8是,在该链上加一个,会将table容量为32,在加一个,或扩容为64,在加一个就会转化为红黑树;

4、HashTable集合

1、基本情况

  • 存放的是键值对
  • hashtable的键和值不能为null,
  • hashtable使用方法基本上和HashMap一样
  • HashTable是线程安全,HashMap非线程安全

2、底层结构

  • .底层是一个数组 + 链表

  • 初始化的长度为11;

  • 临界值为0.75 =* 11 = 8;

  • 扩容:

    第一次为11;

    第二次为11 * 2 + 1 = 23;

5、HashMap和HashTable的比较

HashMapHashTable
版本1.21.0
线程安全非线程安全线程安全
效率较低
允许null键和null值可以不可以
初始的容量和每次扩容的大小不同默认为null,第一次添加,初始为16,扩容为原来的2倍默认为长度为11,扩容为原来的两倍 + 1;
计算Hash值得方式不同是使用自定义的哈希算法。没有自定义哈希算法,而直接采用的key的hashCode()

6、TreeMap

  • 在构造方法中可以传入比较器
  • 可以进行排序
  • 存放的是键值对
  • 基于红黑树对所有的的key进行排序
  • 自然排序和定值排序
  • 底层是红黑树
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值