摘要:在開始了解的原理之前,首先看一段代碼,在這里以阿里的為例。翻開的源碼可以發(fā)現(xiàn),在其節(jié)點(diǎn)類里面,在的基礎(chǔ)上又添加了一個和指針,那么這兩個指針就是雙向鏈表的指針??偨Y(jié)其實(shí)每一個的設(shè)計(jì)都是很精妙的
在開始了解Json的原理之前,首先看一段代碼,在這里以阿里的FastJson為例。
public class JsonRun { public static void main(String[] args) { JSONObject jsonObject =new JSONObject(); jsonObject.put("id","a"); jsonObject.put("name","b"); System.out.println(jsonObject.toJSONString()); } }
當(dāng)看到上述代碼的時候,可能一般的程序員都會想到的是輸出為如下Json串
{"id":"a","name":"b"}
但是運(yùn)行這段程序,你會發(fā)現(xiàn)控制臺打印出來的是如下代碼:
{"name":"b","id":"a"}
那么為什么會出現(xiàn)這種情況呢,翻開FastJson的源碼便知道了,首先定位到 JsonObject 這個類的構(gòu)造函數(shù),如下:
public JSONObject(int initialCapacity, boolean ordered){ if (ordered) { map = new LinkedHashMap(initialCapacity); } else { map = new HashMap (initialCapacity); } }
這里的 ordered 為一個構(gòu)造參數(shù),表示的是是否按照順序添加,此處先不管,然后可以發(fā)現(xiàn)在阿里的FastJson中,其實(shí)默認(rèn)的Json實(shí)現(xiàn)是一個Map,那么對于LinkedHashMap來講,它是一個map和雙向鏈表的整合體,所以在LinkedList中,每一個Node都會有一個前指針和一個后指針
HashMapLinkedHashMap 是一個HashMap的變種,大家都知道,一個HashMap是由一個桶和一個桶后面的節(jié)點(diǎn)組成的,而桶其實(shí)是一個數(shù)組,每一個桶的索引所對應(yīng)的值都是由Hash()函數(shù)計(jì)算得出的。那么這樣就會導(dǎo)致桶的元素是一個亂序的存儲的,例如在本段代碼中的id和name,它們所在的桶索引可能是:
這樣就導(dǎo)致了一個問題,就是Json的鍵的順序是無法保證的,那么既然HashMap是無法保證的,為什么LinkedHashMap卻可以保證順序。
LinkedHashMap翻開LinkedHashMap的源碼可以發(fā)現(xiàn),在其節(jié)點(diǎn)類里面,LinkedHashMap在 HashMap的Entry基礎(chǔ)上又添加了一個before和after指針,
static class Entryextends HashMap.Node { Entry before, after; Entry(int hash, K key, V value, Node next) { super(hash, key, value, next); } }
那么這兩個指針就是雙向鏈表的指針。有了這兩個指針之后,每一個新插入的節(jié)點(diǎn)都會知道他的前驅(qū)結(jié)點(diǎn)和后置節(jié)點(diǎn),那么對于LinkedHashMap的插入順序就會有保證了。所以其對應(yīng)的數(shù)據(jù)結(jié)構(gòu)如圖:
在這個結(jié)構(gòu)里面,桶索引是id的第一個節(jié)點(diǎn)是一個頭節(jié)點(diǎn),在新插入name的時候,LinkedHashMap會將head節(jié)點(diǎn)的after指針指向name,所以雖然這是一個HashMap,但是它的順序還是可以保證的。
LinkedHashMap的迭代區(qū)別于HashMap以索引的方式進(jìn)行迭代,LinkedHashMap是以鏈表的指針進(jìn)行迭代的,如以下代碼所示:
abstract class LinkedHashIterator { LinkedHashMap.Entrynext; LinkedHashMap.Entry current; int expectedModCount; LinkedHashIterator() { next = head; expectedModCount = modCount; current = null; } final LinkedHashMap.Entry nextNode() { LinkedHashMap.Entry e = next; //next就是head節(jié)點(diǎn) if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); current = e; next = e.after; //此處每一次的迭代都是鏈表的after return e; }
可以看到在每一次迭代的時候LinkedHashMap都是以鏈表的next節(jié)點(diǎn)作為下一個迭代,那么HashMap呢?
HashMap的迭代abstract class HashIterator { Nodenext; // next entry to return Node current; // current entry int expectedModCount; // for fast-fail int index; // current slot HashIterator() { expectedModCount = modCount; Node [] t = table; current = next = null; index = 0; if (t != null && size > 0) { // advance to first entry do {} while (index < t.length && (next = t[index++]) == null); } } final Node nextNode() { Node [] t; Node e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null); } return e; }
注意這一段代碼
if (t != null && size > 0) { // advance to first entry do {} while (index < t.length && (next = t[index++]) == null); }
這一段代碼的作用是找出table[]中第一個不為null的桶,所以其實(shí)HashMap的迭代就是依據(jù)桶中的順序來的,但是LinkedHashMap則是按找鏈表的順序來的。
總結(jié)其實(shí)每一個java的設(shè)計(jì)都是很精妙的...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/77055.html
摘要:今天逛了逛,順手精選出了一下近幾個月以來上最熱門的個項(xiàng)目。相關(guān)閱讀正式開源,幫助應(yīng)用快速容器化未來可能會上熱門的項(xiàng)目地址介紹哈哈,皮一下很開心。這是我自己開源的一份文檔,目前仍在完善中,歡迎各位英雄好漢一起完善。 showImg(https://segmentfault.com/img/remote/1460000015766827?w=391&h=220);今天逛了逛Github,順...
摘要:云加速服務(wù)商日前宣布,正式推出實(shí)時狀態(tài)與性能監(jiān)控功能。的實(shí)時狀態(tài)和性能監(jiān)控,覆蓋全國所有省份,幫助所有用戶直接全面了解服務(wù)情況,及時發(fā)現(xiàn)定位和解決突發(fā)問題,實(shí)現(xiàn)產(chǎn)品性能的最大優(yōu)化。 云加速服務(wù)商 UPYUN 日前宣布,正式推出 CDN 實(shí)時狀態(tài)與性能監(jiān)控功能。通過對全國 120 個 CDN 節(jié)點(diǎn)日志的數(shù)據(jù)分析,將速度、耗時、ISP 線路、地區(qū)、請求占比等多維度的精準(zhǔn)數(shù)據(jù),以地圖的方式具...
摘要:應(yīng)用常見安全漏洞一覽注入注入就是通過給應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的命令。此外,適當(dāng)?shù)臋?quán)限控制不曝露必要的安全信息和日志也有助于預(yù)防注入漏洞。 web 應(yīng)用常見安全漏洞一覽 1. SQL 注入 SQL 注入就是通過給 web 應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的 SQL 命令。 SQL 注入漏洞屬于后端的范疇,但前端也可做體驗(yàn)上的優(yōu)化。 原因 當(dāng)使用外...
摘要:應(yīng)用常見安全漏洞一覽注入注入就是通過給應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的命令。此外,適當(dāng)?shù)臋?quán)限控制不曝露必要的安全信息和日志也有助于預(yù)防注入漏洞。 web 應(yīng)用常見安全漏洞一覽 1. SQL 注入 SQL 注入就是通過給 web 應(yīng)用接口傳入一些特殊字符,達(dá)到欺騙服務(wù)器執(zhí)行惡意的 SQL 命令。 SQL 注入漏洞屬于后端的范疇,但前端也可做體驗(yàn)上的優(yōu)化。 原因 當(dāng)使用外...
摘要:番茄工作法簡約而不簡單,本書亦然。在番茄工作法一個個短短的分鐘內(nèi),你收獲的不僅僅是效率,還會有意想不到的成就感。 @author ASCE1885的 Github 簡書 微博 CSDN 知乎本文由于潛在的商業(yè)目的,不開放全文轉(zhuǎn)載許可,謝謝! showImg(/img/remote/1460000007319503?w=728&h=792); 廣而告之時間:我的新書《Android 高...
閱讀 3556·2021-11-22 11:59
閱讀 954·2021-09-27 13:36
閱讀 3616·2021-09-24 09:47
閱讀 2266·2021-09-01 11:39
閱讀 985·2021-08-31 09:37
閱讀 2316·2021-08-05 10:01
閱讀 1677·2019-08-30 15:55
閱讀 703·2019-08-30 15:54