资讯专栏INFORMATION COLUMN

Json底层一览

Stardustsky / 3498人阅读

摘要:在开始了解的原理之前,首先看一段代码,在这里以阿里的为例。翻开的源码可以发现,在其节点类里面,在的基础上又添加了一个和指针,那么这两个指针就是双向链表的指针。总结其实每一个的设计都是很精妙的

在开始了解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(initialCapacity);
        } else {
            map = new HashMap(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 extends HashMap.Node {
        Entry before, after;
        Entry(int hash, K key, V value, Node next) {
            super(hash, key, value, next);
        }
    }

那么这两个指针就是双向链表的指针。有了这两个指针之后,每一个新插入的节点都会知道他的前驱结点和后置节点,那么对于LinkedHashMap的插入顺序就会有保证了。所以其对应的数据结构如图:

在这个结构里面,桶索引是id的第一个节点是一个头节点,在新插入name的时候,LinkedHashMap会将head节点的after指针指向name,所以虽然这是一个HashMap,但是它的顺序还是可以保证的。

LinkedHashMap的迭代

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

abstract class LinkedHashIterator {
        LinkedHashMap.Entry next;
        LinkedHashMap.Entry current;
        int expectedModCount;

        LinkedHashIterator() {
            next = head;
            expectedModCount = modCount;
            current = null;
        }


final LinkedHashMap.Entry nextNode() {
            LinkedHashMap.Entry 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 next;        // 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的桶,所以其实HashMap的迭代就是依据桶中的顺序来的,但是LinkedHashMap则是按找链表的顺序来的。

总结

其实每一个java的设计都是很精妙的...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77055.html

相关文章

  • 近几个月Github上最热门的Java项目一览

    摘要:今天逛了逛,顺手精选出了一下近几个月以来上最热门的个项目。相关阅读正式开源,帮助应用快速容器化未来可能会上热门的项目地址介绍哈哈,皮一下很开心。这是我自己开源的一份文档,目前仍在完善中,欢迎各位英雄好汉一起完善。 showImg(https://segmentfault.com/img/remote/1460000015766827?w=391&h=220);今天逛了逛Github,顺...

    cyqian 评论0 收藏0
  • UPYUN首创CDN实时监控,性能状态一览无遗

    摘要:云加速服务商日前宣布,正式推出实时状态与性能监控功能。的实时状态和性能监控,覆盖全国所有省份,帮助所有用户直接全面了解服务情况,及时发现定位和解决突发问题,实现产品性能的最大优化。 云加速服务商 UPYUN 日前宣布,正式推出 CDN 实时状态与性能监控功能。通过对全国 120 个 CDN 节点日志的数据分析,将速度、耗时、ISP 线路、地区、请求占比等多维度的精准数据,以地图的方式具...

    lingdududu 评论0 收藏0
  • web 应用常见安全漏洞一览

    摘要:应用常见安全漏洞一览注入注入就是通过给应用接口传入一些特殊字符,达到欺骗服务器执行恶意的命令。此外,适当的权限控制不曝露必要的安全信息和日志也有助于预防注入漏洞。 web 应用常见安全漏洞一览 1. SQL 注入 SQL 注入就是通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令。 SQL 注入漏洞属于后端的范畴,但前端也可做体验上的优化。 原因 当使用外...

    darkerXi 评论0 收藏0
  • web 应用常见安全漏洞一览

    摘要:应用常见安全漏洞一览注入注入就是通过给应用接口传入一些特殊字符,达到欺骗服务器执行恶意的命令。此外,适当的权限控制不曝露必要的安全信息和日志也有助于预防注入漏洞。 web 应用常见安全漏洞一览 1. SQL 注入 SQL 注入就是通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令。 SQL 注入漏洞属于后端的范畴,但前端也可做体验上的优化。 原因 当使用外...

    Panda 评论0 收藏0
  • Android 研发工程师图书一览(2016年版)

    摘要:番茄工作法简约而不简单,本书亦然。在番茄工作法一个个短短的分钟内,你收获的不仅仅是效率,还会有意想不到的成就感。 @author ASCE1885的 Github 简书 微博 CSDN 知乎本文由于潜在的商业目的,不开放全文转载许可,谢谢! showImg(/img/remote/1460000007319503?w=728&h=792); 广而告之时间:我的新书《Android 高...

    MadPecker 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<