淺析Json底層

在開始瞭解Json的原理以前,首先看一段代碼,在這裏以阿里的FastJson爲例。java

 
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());
 
  }
 
} 

當看到上述代碼的時候,可能通常的程序員都會想到的是輸出爲以下Json程序員

 

{"id":"a","name":"b"}

可是運行這段程序,你會發現控制檯打印出來的是以下代碼:

{"name":"b","id":"a"}

 

那麼爲何會出現這種狀況呢,翻開FastJson的源碼便知道了,首先定位到 JsonObject 這個類的構造函數,以下:json

 

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

這裏的 ordered 爲一個構造參數,表示的是是否按照順序添加,此處先無論,而後能夠發如今阿里的FastJson中,其實默認的Json實現是一個Map,那麼對於LinkedHashMap來說,它是一個map和雙向鏈表的整合體,因此在LinkedList中,每個Node都會有一個前指針和一個後指針數組

HashMap

LinkedHashMap 是一個HashMap的變種,你們都知道,一個HashMap是由一個桶和一個桶後面的節點組成的,而桶實際上是一個數組,每個桶的索引所對應的值都是由Hash()函數計算得出的。那麼這樣就會致使桶的元素是一個亂序的存儲的,例如在本段代碼中的idname,它們所在的桶索引多是:
數據結構

這樣就致使了一個問題,就是Json的鍵的順序是沒法保證的,那麼既然HashMap是沒法保證的,爲何LinkedHashMap卻能夠保證順序。函數

LinkedHashMap

翻開LinkedHashMap的源碼能夠發現,在其節點類裏面,LinkedHashMap在 HashMap的Entry基礎上又添加了一個beforeafter指針,spa

 
static class Entry<K,V> extends HashMap.Node<K,V> {
 
    Entry<K,V> before, after;
 
    Entry(int hash, K key, V value, Node<K,V> next) {
 
    super(hash, key, value, next);
 
    }
 
}

那麼這兩個指針就是雙向鏈表的指針。有了這兩個指針以後,每個新插入的節點都會知道他的前驅結點和後置節點,那麼對於LinkedHashMap的插入順序就會有保證了。因此其對應的數據結構如圖:指針

在這個結構裏面,桶索引是id的第一個節點是一個頭節點,在新插入name的時候,LinkedHashMap會將head節點的after指針指向name,因此雖然這是一個HashMap,可是它的順序仍是能夠保證的。code

LinkedHashMap的迭代

區別於HashMap以索引的方式進行迭代,LinkedHashMap是以鏈表的指針進行迭代的,如如下代碼所示:blog

 
abstract class LinkedHashIterator {
 
LinkedHashMap.Entry<K,V> next;
 
LinkedHashMap.Entry<K,V> current;
 
int expectedModCount;
 
 
 
LinkedHashIterator() {
 
next = head;
 
expectedModCount = modCount;
 
current = null;
 
}
 
 
 
 
 
final LinkedHashMap.Entry<K,V> nextNode() {
 
LinkedHashMap.Entry<K,V> e = next; //next就是head節點
 
if (modCount != expectedModCount)
 
throw new ConcurrentModificationException();
 
if (e == null)
 
throw new NoSuchElementException();
 
current = e;
 
next = e.after; //此處每一次的迭代都是鏈表的after
 
return e;
 
}

  

能夠看到在每一次迭代的時候LinkedHashMap都是以鏈表的next節點做爲下一個迭代,那麼HashMap呢?

HashMap的迭代

abstract class HashIterator {
 
  Node<K,V> next; // next entry to return
 
  Node<K,V> current; // current entry
 
  int expectedModCount; // for fast-fail
 
  int index; // current slot
 
 
 
HashIterator() {
 
  expectedModCount = modCount;
 
  Node<K,V>[] 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<K,V> nextNode() {
 
  Node<K,V>[] t;
 
  Node<K,V> 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的桶,因此其實HashMap的迭代就是依據桶中的順序來的,可是LinkedHashMap則是按找鏈表的順序來的。

總結

JSON底層爲一個Map,根據傳入的參數選擇有序的HashMap仍是無序的LinkedHashMap。

相關文章
相關標籤/搜索