作为一名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-
往期推荐
更多精彩,请扫二维码
你若喜欢,请帮忙点【在看】