浅析Json底层
在开始了解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()
函数计算得出的。那么这样就会导致桶的元素是一个乱序的存储的,例如在本段代码中的id
和name
,它们所在的桶索引可能是:
这样就导致了一个问题,就是Json的键的顺序是无法保证的,那么既然HashMap是无法保证的,为什么LinkedHashMap却可以保证顺序。
LinkedHashMap
翻开LinkedHashMap的源码可以发现,在其节点类里面,LinkedHashMap在 HashMap的Entry基础上又添加了一个before
和after
指针,
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底层的更多相关文章
- 微博CacheService架构浅析 对底层协议进行适配
https://mp.weixin.qq.com/s/wPR0j2bmHBF6z0ZjTlz_4A 麦俊生 InfoQ 2014-04-21 微博作为国内最大的社交媒体网站之一,每天承载着亿万用户的服 ...
- iOS - 分析JSON、XML的区别和解析方式的底层是如何实现的(延伸实现原理)
<分析JSON.XML的区别,JSON.XML解析方式的底层是如何实现的(延伸实现原理)> (一)JSON与XML的区别: (1)可读性方面:基本相同,XML的可读性比较好: (2)可扩展 ...
- 【原】iOS学习之XML与JSON两种数据结构比较和各自底层实现
1.XML与JSON两种数据结构的优缺点 1> XML 优点: 格式统一, 符合标准 容易与其他系统进行远程交互, 数据共享比较方便 缺点: XML文件格式文件庞大, 格式复杂, 传输占 ...
- 转载Json和Xml的区别,以及它们的底层是如何处理的
XML:可扩展标记语言 JSON:轻量级的数据交换格式 区别: 1.可读性方面:基本相同,Xml的可读性较好些: 2.可扩展性方面:都有较好的扩展性: 3.编码难度方面:json的编码较容 ...
- 数据解析(XML和JSON数据结构)
一 解析 二 XML数据结构 三 JSON 数据结构 一 解析 1 定义: 从事先规定好的格式中提取数据 解析的前提:提前约定好格式,数据提供方按照格式提供数据.数据获取方则按照 ...
- 运用 三种 原生 谷歌 阿里 解析和生成json
三种类生成JSON数据方法 JSON(原生): 第一种 JSONStringer和JSONObject区别在于添加对象时是按顺序添加的比如说 JSONStringer 添加 a:1 b:2 c:3那么 ...
- json数据结构
JSON即JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合服务器与JavaScript的交互.JSON易于人阅读和编写.同时也易于机器解析和生成.JSON采 ...
- 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)
目录 1. 前言 2. 闭锁CountDownLatch 2.1 CountDownLatch功能简介 2.2 使用CountDownLatch 2.3 CountDownLatch原理浅析 3.循环 ...
- iOS 底层框架的浅析
1.简介 IOS是由苹果公司为iPhone.iPod touch和iPad等设备开发的操作系统. 2.知识点 iPhone OS(现在叫iOS)是iPhone, iPod touch 和 iPad 设 ...
随机推荐
- OpenCV.概念(读书笔记)
ZC:学习OpenCV.pdf 1.多通道矩阵(学习OpenCV.pdf) 1.1.在学习opencv的时候看到多通道矩阵这一概率,恳求大神告诉我一下什么意思_百度知道.html(https://zh ...
- 最新 波克城市java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.波克城市等10家互联网公司的校招Offer,因为某些自身原因最终选择了波克城市.6.7月主要是做系统复习.项目复盘.Leet ...
- springBoot--组合注解RestController,GetMapping,PostMapping
一.RestController @RestController 是@Controller和@ResponseBody的缩写 二.@getMapping和PostMapping @GetMapping ...
- thinkphp5相关
THINKPHP5代码风格规范(基于PSR): https://www.jianshu.com/p/e53d26407e68
- hdoj4276(树形dp+分组背包)
题目链接:https://vjudge.net/problem/HDU-4276 题意:给出一棵树,起点为1,时间为V,终点为n,每个点有一个价值a[u],每条边有一个时间花费w,求在时间V内到达终点 ...
- JS对字符串的操作,截取
substring() //一个参数的时候是从那个参数到字符串结束的位置: substring(start,stop) //substring是对字符串两个索引之间的值进行截取: 要注 ...
- Guava 工具类之joiner的使用
joiner主要用于对字符串的连接,也可用于对map中key value的连接 public class JoinerTest { private static final List<Strin ...
- [转帖]ECC公钥格式详解
ECC公钥格式详解 https://www.cnblogs.com/xinzhao/p/8963724.html 本文首先介绍公钥格式相关的若干概念/技术,随后以示例的方式剖析DER格式的ECC公钥, ...
- mysql在字符编辑窗口下怎么退出编辑界面?(mysql下的ctrl+c与\c)
[1]SQL编辑 我们在SQL编辑的时候打错了,想要退出编辑重新输入,或者是不想写了. 如下图 (1)如果我们直接按ctrl+c中断,那么直接退出整个linux了,如上图 (2)我们可以使用\c,直接 ...
- Thinking In Java 4th Chap3 操作符
若String后接一‘+’运算符,其后元素自动转化为String类型 注意:若对对象赋值另一对象,操作对应的是引用,如c=d,则c和d都指向原来d指向的对象 生成随机数:Random rand=new ...