面试官:“小伙子,你都工作两年了,怎么还只会用不知道原理啊”

作为一名java程序员,求职面试时,关于集合的问题时常会遇到。

张工是一名java程序员,最近到某互联网公司面试,面试官提出这样的一个问题:

说说你知道的HashMap和LinkedHashMap有什么区别?

张工印象中只记得LinkedHashMap能够保证顺序性。

面试官:它是如何做到保证顺序性?

张工一时回答不上来。

面试官:小伙子,你都工作两年了,怎么还是只会用,而不知道原理。

被面试官这么一说,张工都不好意思了。

 

关于LinkedHashMap顺序性,在实际开发中我们时常会遇到。我就遇到过类似的情况,一次是在查询后台数据时,想根据查询结果生成文件,结果发现生成的文件内容顺序跟想要的顺序不一致,以为是遍历的时候put错位了,经过检查发现并不是这个原因。

 

之前在做Android购物车模块展示商品sku时, 用HashMap解析服务端返回json也遇到类似问题,后来改成LinkedHashMap就可以了。

 

想想这问题应该类似,于是查看JsonObject源码,果然,JsonObject内部是用HashMap来存储的,我们知道HashMap输出是按key的排序来的,如果要让JsonObject按照我们put的先后顺序来输出,可以从JsonObject类的构造方法入手。

JsonObject类构造方法:

private static final long   serialVersionUID  = 1L;
private static final int   DEFAULT_INITIAL_CAPACITY = 16;
private final Map<String, Object> map;
public JSONObject(){
    this(DEFAULT_INITIAL_CAPACITY, false);
}
public JSONObject(Map<String, Object> map){
    if (map == null) {
        throw new IllegalArgumentException("map is null.");
    }
    this.map = map;
}

public JSONObject(boolean ordered){
    this(DEFAULT_INITIAL_CAPACITY, ordered);
}

public JSONObject(int initialCapacity){
    this(initialCapacity, false);
}

public JSONObject(int initialCapacity, boolean ordered){
    if (ordered) {
        map = new LinkedHashMap<String, Object>(initialCapacity);
    } else {
        map = new HashMap<String, Object>(initialCapacity);
    }
}

从JSONObject的构造方法我们可以看到,是采用HashMap还是LinkedHashMap完全可以由我们决定, 这样我们就通过下面两种方式实现我们指定的排序:

1、JSONObject jsonObj = new JSONObject(new LinkedHashMap<String, Object>());

2、JSONObject jsonObj = new JSONObject(true);

编译再次运行,生成的文件就和我们put的顺序是一致的了。

 

回到前面的问题来,LinkedHashMap是如何做到遍历时按照插入顺序输出呢? 原因在于LinkedHashMap的内部类LinkedHashIterator,执行iterator.next访问链表下一个元素, 即链表先后顺序。

 abstract class LinkedHashIterator {
    LinkedHashMap.Entry<K,V> next;
    LinkedHashMap.Entry<K,V> current;
    int expectedModCount;

    LinkedHashIterator() {
        next = head;
        expectedModCount = modCount;
        current = null;
    }

    public final boolean hasNext() {
        return next != null;
    }

    final LinkedHashMap.Entry<K,V> nextNode() {
        LinkedHashMap.Entry<K,V> e = next;
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (e == null)
            throw new NoSuchElementException();
        current = e;
        next = e.after;
        return e;
    }

    public final void remove() {
        Node<K,V> p = current;
        if (p == null)
            throw new IllegalStateException();
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        current = null;
        K key = p.key;
        removeNode(hash(key), key, null, false, false);
        expectedModCount = modCount;
    }
}

由此从我们可以得知, LinkedHashMap之所以能够保持顺序,是因为它维护了双向链表。

 

有些问题只要我们进一步跟进,其实都不难发现答案的。

有人说LinkedHashMap是有序的,而HashMap是无序的,个人觉得这种表达不太严谨,HashMap虽说是无序其实也有迹可循的, 也可以按照桶下标先后排序;如果有哈希碰撞的情况,则同一个桶位置按照链表先后顺序输出。

 

总结:

关于LinkedHashMap如何能保证有序的就先分享到这,建议平时工作中要注意总结和积累,查漏补缺,不断完善自己的知识体系。

 

由于笔者水平有限,文中纰漏之处在所难免,权当抛砖引玉,不妥之处,请大家批评指正。

 

-END-

往期推荐

阿里CEO张勇认为程序员不应限制年龄

更多精彩,请扫二维码

你若喜欢,请帮忙点【在看

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值