Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 534|回复: 0

FastJson遇见的问题或项目实战中优化的问题,看源码都可以解决

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-17 02:06:44 | 显示全部楼层 |阅读模式

    1:感觉见鬼了一般存储JSONObject中的字段竟然不见了? 

     

            JSONObject object=new JSONObject();
            Map fields = new HashMap();
            fields.put("1","1");
            object.put("fields",fields);
            System.out.println(object.toString());
            JSONObject newFields = object.getJSONObject("fields");
            newFields.put("2",2);
            //TODO  序列化字符串没有2?!!
            // 看源码便可以知晓,当我们使用Map当做JSONObject解析时候,Fastjson会返回一个新的对象
            System.out.println(object.toString());
    

      

    com.alibaba.fastjson.JSON#toJSON(java.lang.Object, com.alibaba.fastjson.serializer.SerializeConfig)源码:

     public static Object toJSON(Object javaObject, SerializeConfig config) {
            if (javaObject == null) {
                return null;
            }
    
            if (javaObject instanceof JSON) {
                return javaObject;
            }
    
            if (javaObject instanceof Map) {
                Map<Object, Object> map = (Map<Object, Object>) javaObject;
            // 创建了一个新的JSONObject返回了
                JSONObject json = new JSONObject(map.size());
    
                for (Map.Entry<Object, Object> entry : map.entrySet()) {
                    Object key = entry.getKey();
                    String jsonKey = TypeUtils.castToString(key);
                    Object jsonValue = toJSON(entry.getValue());
                    json.put(jsonKey, jsonValue);
                }
    
                return json;
            }
    

      

    2:当我们使用JSONArray时候,有些时候里面可能存储较大量的数据,但是有些场景需要在指定index处进行insert操作,这时由于JSONArray默认底层使用的是ArrayList存储,因此存在性能问题,那么是否可以使用LinkedList呢?答案可以的:

     JSONArray arr = new JSONArray(new LinkedList());
    

      

    3:当我们查询接口获取到一个JSONArray字符串想反序列化时候可否将底层存储的ArrayList使用LinkedList替换呢?答案:可以,修改一下源码或者添加一个重载方法即可。

     public static JSONArray parseArray(String text) {
            if (text == null) {
                return null;
            }
    
            DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance());
    
            JSONArray array;
    
            JSONLexer lexer = parser.lexer;
            if (lexer.token() == JSONToken.NULL) {
                lexer.nextToken();
                array = null;
            } else if (lexer.token() == JSONToken.EOF) {
                array = null;
            } else {
    //            array = new JSONArray(new ArrayList());
                array = new JSONArray(new LinkedList());
                parser.parseArray(array);
    
                parser.handleResovleTask(array);
            }
    
            parser.close();
    
            return array;
        }
    

     

    4:当我们调用方法返回一个含有大量的元素的JSONArray时候该如何进行插入?

    问题3中的是字符串我们解析时候可以自定义解析为LinkedList,但是当我们获取的是一个JSONArray时候该如何处理?难道还有序列化字符串在反序列化到底层存储为LinkedList的JSONArray吗?答案不需要,我们可以借助java的System的arrcopy方法高效完成转换:

         //加入我们有一个比较大的list,想在中间高效插入元素
            List<Integer> list = Lists.newArrayList(1, 2, 3, 5);//Lists来至于Guava
            Integer[] iarr = new Integer[5]; // 相比如add(index,e)耗费时间位置所在
         //对于顺序存储的ArrayList而言,toArray方法的底层实现也是使用的System.arrcopy方法进行高效生成数组 Integer[] arr1 = list.toArray(new Integer[0]); Integer[] arr2 = new Integer[]{1, 2, 3}; //TODO 高效复制 System.arraycopy(arr1, 0, iarr, 0, 3); //模拟中间插入元素 iarr[3] = 4; //TODO 高效复制 System.arraycopy(arr1, 3, iarr, 4, 1); //java.util.Arrays.ArrayList // Arrays的asList方法效率高,原因是直接将传入的数组作为Arrays.ArrayList的底层存储容器 List ret = Arrays.asList(iarr); System.out.println(ret.getClass()); JSONArray retArr = new JSONArray(ret); System.out.println(JSON.toJSONString(retArr));

     该点存在错误,经过实际测试发现该方案比ArraList的add(index,e)普遍要慢,原因首先还是看一下ArrayList的add(index,e)方法:

        public void add(int index, E element) {
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1,
                             size - index);
            elementData[index] = element;
            size++;
        }
    

      看源码可以发现add(index,e)使用的也是arraycopy,那为什么要快呢?认真看arraycopy的参数都是elementData,而且该数组通常容量都是已经扩容好的,在极有少数情况下需要扩容。但是上述4中的方法需要我们自己初始化一个数组,该数组大小等于current+addSize,初始化该数组比较耗费时间。 

    注意: JDK的ArrayList扩容使用的是内存复制,并不是逐个移动元素。JDK开发者还是很聪明的。

     

    5:在4中我们可以发现使用素组高效创建ArrayList的方法时:

    List ret = Arrays.asList(1,2,3,4);

    底层不是进行for循环逐个插入,而是直接使用数组作为ArrayList的底层存储。

     

    但是需要特别注意:

    此处的ArrayList不是java.util.ArrayList,而是class java.util.Arrays.ArrayList 。但是class java.util.Arrays.ArrayList也是java.util.List的子类实现,由于java多态存在因此不存在类型的限制。

     

    6: 同于顺序存储的ArrayList的toArray方法底层使用的是内存复制生成数组,高效率。

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 19:42 , Processed in 0.065139 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表