zoukankan      html  css  js  c++  java
  • HashMap存入和取出数据顺序不一致

    一、HashMap 乱序问题介绍

    HashMap 是我们在开发中常用的Map数据结构,它根据 HashCode的值存储数据,根据键进行取值,具有很快的访问速度。

    关于HashMap的缺点我们知道它是线程不安全的,这里我们可以通过Collections.synchronizedMap()方法或者使用ConcurrentHashMap来解决同步问题。

    这里要指出来的一点是,HashMap存取是乱序的,下面我们通过一个实例看一下:

    public class HashMapTest {
        public static void main(String[] args) {
            Map<String, String> hashMap = new HashMap<String, String>();
            hashMap.put("key0", "value0");
            hashMap.put("key1", "value1");
            hashMap.put("key2", "value2");
            Set<Map.Entry<String, String>> set = hashMap.entrySet();
            for (Map.Entry entry : set) {
                String key = (String) entry.getKey();
                String value = (String) entry.getValue();
                System.out.println("key:" + key + ",value:" + value);
            }
        }
    }

    输出结果:

    key:key1,value:value1
    key:key2,value:value2
    key:key0,value:value0

    可以看到,我们是按照xxx1、xxx2、xxx3的顺序插入的,但是输出结果并不是按照顺序的。

    此问题在实际开发中可能存在的场景:Map作为容器提交请求参数,但是如果使用HashMap进行存储,则在用于上传图片的时候,会出现图片乱序的问题。

    二、解决HashMap乱序问题的方案

    解决方案为:使用LinkedHashMap

    public static void main(String[] args) {
        Map<String, String> hashMap = new LinkedHashMap<>();
        hashMap.put("key0", "value0");
        hashMap.put("key1", "value1");
        hashMap.put("key2", "value2");
        Set<Map.Entry<String, String>> set = hashMap.entrySet();
        for (Map.Entry entry : set) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            System.out.println("key:" + key + ",value:" + value);
        }
    }

    输出结果:

    key:key0,value:value0
    key:key1,value:value1
    key:key2,value:value2

    三、LinkedHashMap 说明

    LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。

    LinkedHashMap继承自HashMap,是基于HashMap的基础之上进行的扩展:

    public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {

    构造函数基本上也是super的HashMap的构造函数,这里特别说明一下其中一个构造函数:

     public LinkedHashMap(int initialCapacity,  float loadFactor, boolean accessOrder) {
         super(initialCapacity, loadFactor);
         this.accessOrder = accessOrder;
    }

    前面两个参数 initialCapacity 和 loadFactor 都是比较熟悉的,分别为初始容量和负载因子。这里我们着重说一下 accessOrder,如果将accessOrder设置为false,表示不是访问顺序而是插入顺序存储的,这也是默认值,表示LinkedHashMap中存储的顺序是按照调用put方法插入的顺序进行排序的。这表示LinkedHashMap存储顺序有两种:插入顺序 和 访问顺序。

    以下是两篇很好的文章,帮助大家基于源码理解LinkedHashMap:

    1. LinkedHashMap 源码详细分析(JDK1.8)

    2. 图解LinkedHashMap原理(JDK1.7)

    总结一下:

    LinkedHashMap的特点如下:

    • LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
    • HashMap无序;LinkedHashMap有序,可分为插入顺序和访问顺序两种。如果是访问顺序,那put和get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插入)。
    • LinkedHashMap存取数据,还是跟HashMap一样使用的Entry[]的方式,双向链表只是为了保证顺序。
    • LinkedHashMap是线程不安全的。

    LinkedHashMap的使用场景:

    • LinkedHashMap可以实现LRU算法

     

     

  • 相关阅读:
    虚拟主机支持apk
    pc显示,手机隐藏
    manjaro个人配置
    docker-compose部署elk
    docker-compose部署zk和kafka
    docker-compose部署redis-cluster
    ActiveMQ与RocketMQ对比
    dropbox离线安装包--需FQ
    C++实现中缀表达式转前、后缀
    运算符优先级
  • 原文地址:https://www.cnblogs.com/renhui/p/12145581.html
Copyright © 2011-2022 走看看