在开始了解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());

  }

} 

当看到上述代码的时候,可能一般的程序员都会想到的是输出为如下Json

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

但是运行这段程序,你会发现控制台打印出来的是如下代码:

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

那么为什么会出现这种情况呢,翻开FastJson的源码便知道了,首先定位到 JsonObject 这个类的构造函数,如下:

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指针,

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,但是它的顺序还是可以保证的。

LinkedHashMap的迭代

区别于HashMap以索引的方式进行迭代,LinkedHashMap是以链表的指针进行迭代的,如以下代码所示:

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。

浅析Json底层的更多相关文章

  1. 微博CacheService架构浅析 对底层协议进行适配

    https://mp.weixin.qq.com/s/wPR0j2bmHBF6z0ZjTlz_4A 麦俊生 InfoQ 2014-04-21 微博作为国内最大的社交媒体网站之一,每天承载着亿万用户的服 ...

  2. iOS - 分析JSON、XML的区别和解析方式的底层是如何实现的(延伸实现原理)

    <分析JSON.XML的区别,JSON.XML解析方式的底层是如何实现的(延伸实现原理)> (一)JSON与XML的区别: (1)可读性方面:基本相同,XML的可读性比较好: (2)可扩展 ...

  3. 【原】iOS学习之XML与JSON两种数据结构比较和各自底层实现

    1.XML与JSON两种数据结构的优缺点 1> XML 优点:
 格式统一, 符合标准
 容易与其他系统进行远程交互, 数据共享比较方便 
 缺点: XML文件格式文件庞大, 格式复杂, 传输占 ...

  4. 转载Json和Xml的区别,以及它们的底层是如何处理的

    XML:可扩展标记语言       JSON:轻量级的数据交换格式 区别: 1.可读性方面:基本相同,Xml的可读性较好些: 2.可扩展性方面:都有较好的扩展性: 3.编码难度方面:json的编码较容 ...

  5. 数据解析(XML和JSON数据结构)

    一   解析 二 XML数据结构 三 JSON 数据结构     一 解析 1  定义: 从事先规定好的格式中提取数据     解析的前提:提前约定好格式,数据提供方按照格式提供数据.数据获取方则按照 ...

  6. 运用 三种 原生 谷歌 阿里 解析和生成json

    三种类生成JSON数据方法 JSON(原生): 第一种 JSONStringer和JSONObject区别在于添加对象时是按顺序添加的比如说 JSONStringer 添加 a:1 b:2 c:3那么 ...

  7. json数据结构

    JSON即JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合服务器与JavaScript的交互.JSON易于人阅读和编写.同时也易于机器解析和生成.JSON采 ...

  8. 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)

    目录 1. 前言 2. 闭锁CountDownLatch 2.1 CountDownLatch功能简介 2.2 使用CountDownLatch 2.3 CountDownLatch原理浅析 3.循环 ...

  9. iOS 底层框架的浅析

    1.简介 IOS是由苹果公司为iPhone.iPod touch和iPad等设备开发的操作系统. 2.知识点 iPhone OS(现在叫iOS)是iPhone, iPod touch 和 iPad 设 ...

随机推荐

  1. 生成SSH秘钥连接github(详细教程)

    第一步.首先,检查下自己之前有没有已经生成: 在开始菜单中打开git下的git bash(当然,在其他目录下打开git bash也是一样的): 然后执行 cd ~/.ssh 第二步.如果能进入到.ss ...

  2. POJ2513 【并查集+欧拉路径+trie树】

    题目链接:http://poj.org/problem?id=2513 Colored Sticks Time Limit: 5000MS   Memory Limit: 128000K Total ...

  3. 将mysql中一行中的几个字段 转换成一列并从其他数据库中查对应的邮件信息

    --将项目中的总监,经理,等的邮箱合并为一行 SELECT GROUP_CONCAT(t.USER_EMAIL SEPARATOR ' ') mail_address FROM portal.t_ac ...

  4. 【AtCoder】AGC004

    AGC004 A - Divide a Cuboid 看哪一维是偶数,答案是0,否则是三个数两两组合相乘中最小的那个 #include <bits/stdc++.h> #define fi ...

  5. http无状态和鉴权解决四种方案

    http协议本身是无状态的,但是在实际的web开发中常有一些操作需要有状态.比如想要访问一些私人访问权限的文章,或者这种操作需要明确当前用户身份. 显然,最简单的方案就是每次都发送账户和密码,但是这样 ...

  6. 1.3Security:权限管理,过滤、监听、拦截

    Security:权限管理 常用权限拦截器 SecurityContextPersistenceFilter 以前是HttpSesstionContextIntegrationFilter,位于过滤器 ...

  7. 二维状压DP经典题

    炮兵阵地 题目链接 题目大意:在n*m的地图上放置炮兵,每个炮兵的攻击范围是上下左右两格内,有两种不同的地形,山地(用"H" 表示),平原(用"P"表示),只有 ...

  8. HTNL基础之四

    11.<nav>导航元素 标签定义及使用说明 表示页面中导航链接的部分,例如:传统导航条,侧边栏导航,页内导航,翻页等 <nav> 标签定义导航链接的部分. 并不是所有的 HT ...

  9. Python 基础(十六)--随机数模块

    random随机数模块 random.randint(1,10):随机1-10包括10 random.randrange(1,10,2):在1.3.5.7.9中随机,类似切片,不包括10 random ...

  10. 关于FSM的C语言实现与详解

    最近一个项目有一个需求,考量了一下决定使用状态机,实现完需求以后,不得不感慨,状态机在处理逻辑上面实现起来很有优势,也便于管理. 在这里分享一下我所修改的状态机实现.改动的地方不多,参考了<C语 ...