Java 中FastJson的使用【吃透FastJson】
如果不了解JSON格式,建议先看下:JSON数据格式【学习记录】
JSON序列化、反序列化JavaBean的框架有很多,最常见的Jackson、阿里巴巴开源的FastJson、谷歌的GSON、apache提供的json-lib等,下面我们主要来熟悉一下:Java语言中FastJson的使用。
FastJson
FastJson是由阿里巴巴工程师基于Java开发的一款Json解析器和生成器,可用于将Java对象转换为其JSON表示形式,它还可以用于将JSON字符串转换为等效的Java对象。FastJson可以处理任意Java对象,包括没有源代码的预先存在的对象。
FastJson使用十分简便,我们只需要在Maven工程的pom文件中引入以下依赖即可:
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.73</version>
</dependency>
FastJson API的入口是com.alibaba.fastjson.JSON,常用的序列化操作都可以在JSON类上的静态方法直接完成。
API测试
我们已经在项目中引入了FastJson的依赖,我们再创建一个用户类用于测试:
package com.test.json;import lombok.Data;@Data
public class User {private Integer id;private String name;private String sex;private Integer age;public User(Builder builder) {this.id = builder.id;this.name = builder.name;this.sex = builder.sex;this.age = builder.age;}public static Builder builder() {return new Builder();}public static class Builder {private Integer id;private String name;private String sex;private Integer age;public Builder name(String name) {this.name = name;return this;}public Builder sex(String sex) {this.sex = sex;return this;}public Builder age(int age) {this.age = age;return this;}public Builder id(int id) {this.id = id;return this;}public User build() {return new User(this);}}
}
一、序列化
序列化就是将JavaBean序列化为JSON字符串,下面我们来看下FastJson常见的序列化方法。
下面序列化相关方法都有统一的返回值类型String。
1)toJsonString(Object o);
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();System.out.println(JSON.toJSONString(user));
}
{"age":23,"id":1,"name":"张三","sex":"男"}
我们通过传入一个对象,便可以将对象转成JSON字符串,这里我们传入的不仅仅是JavaBean还可以是一个Map对象,传入Map对象我们同样也可以取到一个JSON字符串。
public static void main(String[] args) {Map<String, Object> userMap = new HashMap<>();userMap.put("id", 1);userMap.put("name", "张三");userMap.put("sex", "男");userMap.put("age", 23);System.out.println(JSON.toJSONString(userMap));
}
{"age":23,"id":1,"name":"张三","sex":"男"}
List对象也很适用,结果是一个标准的JSONArray的字符串。
public static void main(String[] args) {User zhangsan = User.build().id(1).name("张三").sex("男").age(23).build();User lisi = User.build().id(2).name("李四").sex("女").age(18).build();List<User> userList = new ArrayList<>();userList.add(zhangsan);userList.add(lisi);System.out.println(JSON.toJSONString(userList));
}
[{"id":1,"name":"张三","sex":"男","age":23},{"id":2,"name":"李四","sex":"女","age":18}]
2)toJSONString(Object o, boolean prettyFormat);
如果说 toJSONString(Object o); 的输出结果只有单调的一行让你看起来有点吃力,那么我们可以使用 toJSONString(Object o, boolean prettyFormat); 来让输出结果看起来舒服点。
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();System.out.println(JSON.toJSONString(user, true));
}
{"age":23,"id":1,"name":"张三","sex":"男"
}
通过JSON自带的格式化,让输出结果看起来更加清晰,真是贴心~
3)JSON.toJSONString(Object object, SerializerFeature… features);
我们可以看到这个方法里面有个参数SerializerFeature...,可能感到有点陌生,我们先来看下什么是 SerializerFeature ,通过源码可以发现 SerializerFeature 原来是个枚举类:

源码中都被 @deprecated 注释的实例说明已经废弃了,那有哪些是我们平时经常用到的呢:
| 对象 | 描述 |
|---|---|
| SerializerFeature.UseSingleQuotes | 使用单引号而不是双引号,默认为false |
| SerializerFeature.PrettyFormat | 结果是否格式化,默认为false |
| SerializerFeature.WriteDateUseDateFormat | 如果时间是date、时间戳类型,按照这种格式"yyyy-MM-dd HH:mm"初始化时间 |
| SerializerFeature.WriteMapNullValue | 是否输出值为null的字段,默认为false |
| SerializerFeature.WriteClassName | 序列化时写入类型信息,默认为false |
使用案例:
SerializerFeature.UseSingleQuotes
使用单引号而不是使用双引号,默认为false。
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();System.out.println(JSON.toJSONString(user, SerializerFeature.UseSingleQuotes));
}
{'age':23,'id':1,'name':'张三','sex':'男'}
SerializerFeature.PrettyFormat
结果是否格式化,默认为false。
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();System.out.println(JSON.toJSONString(user));System.out.println("===============");System.out.println(JSON.toJSONString(user, SerializerFeature.PrettyFormat));
}
{"age":23,"id":1,"name":"张三","sex":"男"}
===============
{"age":23,"id":1,"name":"张三","sex":"男"
}
SerializerFeature.WriteDateUseDateFormat
如果时间是Date、时间戳类型,按照这种格式初始化时间"yyyy-MM-dd HH:mm"。
public static void main(String[] args) {System.out.println(JSON.toJSONString(new Date()));System.out.println("===============");System.out.println(JSON.toJSONString(new Date(), SerializerFeature.WriteDateUseDateFormat));
}
1676427576691
===============
"2023-02-15 10:19:37"
通过这种方式我们将日期输出成了固定的格式:yyyy-MM-dd HH:mm,有时候我们不想得到这种格式那该怎么办?通过下面方法支持自定义时间格式:(注意方法不要用错)
4)toJSONStringWithDateFormat(Object object, String dateFormat, SerializerFeature… features);
public static void main(String[] args) {System.out.println(JSON.toJSONString(new Date()));System.out.println("===============");System.out.println(JSON.toJSONStringWithDateFormat(new Date(), "HH:mm:ss"));
}
1676428350771
===============
"10:32:30"
下面我们接着看SerializerFeature枚举类的其他用法。
SerializerFeature.WriteMapNullValue
是否输出值为null的字段,默认为false。
这个有什么用处呢?我们应该很清楚开发规范中鼓励用JavaBean传递参数,尽量减少Map传递参数,因为Map相当于一个黑盒,对于使用者来说根本不知道里面存在哪些字段,而对于创建者来说估计也时常会忘记里面存在哪些字段,为了解决这个痛,JSON也推出了解决方法:
public static void main(String[] args) {Map<String, Object> dataMap = new HashMap<>();dataMap.put("name", null);dataMap.put("age", 23);System.out.println(JSON.toJSONString(dataMap));System.out.println("===============");System.out.println(JSON.toJSONString(dataMap, SerializerFeature.WriteMapNullValue));
}
{"age":23}
===============
{"name":null,"age":23}
通过普通方式的 toJSONString() 方法,空值仿佛被吃掉了,这很可能会成为一个开发灾难!
SerializerFeature.WriteClassName
序列化时写入类信息,默认为false。这个方法可以在反序列化的时候用到,用法如下:
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();System.out.println(JSON.toJSONString(user, SerializerFeature.WriteClssName));
}
{"@type":"com.test.json.User","age":23,"id":1,"name":"张三","sex":"男"}
通过这样我们可以看到我们序列化的对象是什么类型的。
上面这些便是toJSONString的扩展用法,上面说到的是序列化,那么对应的便是反序列化。
二、反序列化
反序列化就是把JSON格式的字符串转换为JavaBean对象。
1)JSONObject parseObject(String text);
public static void main(String[] args){String jsonStr = "{'age':23,'id':1,'name':'张三','sex':'男'}";JSONObject jsonObject = JSON.parseObject(jsonStr);System.out.println(jsonObject.get("name"));
}
张三
用法十分简单,可以将一个标准的JSON字符串转为一个JSONObject对象,由于JSONObject类实现了Map接口,因此我们可以通过get()来获取到值。
我们上述已经说过Map的致命不足,所以我们更希望能得到一个JavaBean对象。
2)<T> T parseObject(String text, Class<T> clazz);
我们通过传入我们想要转换的对象类型,就可以得到我们想要的JavaBean。
public static void main(String[] args){String jsonStr = "{'age':23,'id':1,'name':'张三','sex':'男'}";User user = JSON.parseObject(jsonStr, User.class);System.out.println(user.getName());
}
张三
除了基本反序列化之外,还有一种泛型反序列化可提供使用。
3)<T> T parseObject(String text, TypeReference<T> type, Feature... features);
通过泛型,我们就可以不用传入一个Class对象,而直接获取到我们的JavaBean。
public static void main(String[] args){String jsonStr = "{'age':23,'id':1,'name':'张三','sex':'男'}";User user = JSON.parseObject(jsonStr, new TypeReference<User>(){});System.out.println(user.getName());
}
张三
FastJson序列化还有一个用处那便是进行深克隆。软件设计模式中:原型模式涉及到的深克隆和浅克隆。
浅克隆的实现方式十分简单,我们只需要实现Cloneable接口,然后重写clone()方法:
@Data
class Person {private String name;
}@Data
class NiceCard implements Cloneable {public Person person;public void award() {System.out.println(this.person.getName() + "获得好人卡一张");}public NiceCard clone() throws CloneNotSupportedException {return (NiceCard)super.clone();}
}public class TestClient {public static void main(String[] args) {NiceCard niceCard = new NiceCard();Person person = new Person();person.setName("小李");niceCard.setPerson(person);NiceCard cloneCard = niceCard.clone();Persson clonePerson = cloneCard.getPerson();clonePerson.setName("小王");niceCard.award();cloneCard.award();System.out.println(person == clonePerson);}
}
小王获得一张好人卡
小王获得一张好人卡
true
结果中我们可以看到,好人卡都是属于小王的,这就是浅克隆的弊端了。
我们要想实现深克隆有许多种方式:
- 手动为引用属性赋值
- 借助FastJson
- 使用Java流的序列化对象
方法有很多,我们重点看下FastJson的实现方式:
public static void main(String[] args) {NiceCard niceCard = new NiceCard();Person person = new Person();person.setName("小李");niceCard.setPerson(person);//借助FastJsonNiceCard cloneCard = JSON.parseObject(JSON.toJSONString(niceCard), NiceCard.class);Person clonePerson = cloneCard.getPerson();clonePerson.setName("小王");niceCard.award();cloneCard.award();System.out.println(person == clonePerson);
}
小李获得好人卡一张
小王获得好人卡一张
false
通过FastJson反序列化,我们得到的两个对象实际上是不同的,这也很方便的实现了深克隆。
4)<T> List<T> parseArray(String text, Class<T> clazz);
这是将一个JSON字符串转为JSONArray的方法。
public static void main(String[] args) {String jsonStr = "[{\"id\":1,\"name\":\"张三\",\"sex\":\"男\",\"age\":23},{\"id\":2,\"name\":\"李四\",\"sex\":\"女\",\"age\":18}]";List<User> userList = JSON.parseArray(jsonStr, User.class);userList.forEach(System.out::println);
}
User(id=1, name=张三, sex=男, age=23)
User(id=2, name=李四, sex=女, age=18)
同样我们也可以通过使用泛型序列化来实现同样的功能:
5)List<Object> parseArray(String text, Type[] types);
public static void main(String[] args) {String jsonStr = "[{\"id\":1,\"name\":\"张三\",\"sex\":\"男\",\"age\":23},{\"id\":2,\"name\":\"李四\",\"sex\":\"女\",\"age\":18}]";Type type = new TypeReference<User>() {}.getType();JSON.parseArray(jsonStr, new Type[]{type, type}).forEach(System.out::println);
}
这种方式有个坑就是:我们使用parseArray()这个方法的时候第二个参数需要传入我们要反序列化的对象类型,但是我们这里需要传入的是数组,不知道你有没有为数组里面放了两个一样的type感到奇怪?没错,这就是方法的坑,我们List里面有多少个对象,Type[]这个数组里面的个数要与之匹配,不然会抛出以下错误:

上述JSON串中对象的类型都为User,如果JSON串中存在不同的类型时:
public static void main(String[] args) {String jsonStr = "[{\"id\":1,\"name\":\"张三\",\"sex\":\"男\",\"age\":23},{\"stuName\":\"李四\"}]";Type userType = new TypeReference<User>() {}.getType();Type studentType = new TypeReference<Student>() {}.getType();JSON.parseArray(jsonStr, new Type[]{userType,studentType}).forEach(System.out::println);
}
User(id=1, name=张三, sex=男, age=23)
Student(stuName=李四)
如果将userType和studentType调换顺序,则结果:
Student(stuName=null)
User(id=null, name=null, sex=null, age=null)
三、JavaBean转换为Byte[]
1)toJSONBytes(Object o)
我们平时在进行网络通讯的时候,需要将对象转为字节然后进行传输。我们使用字符串的时候,字符串中有个很便捷的API可以将字符串转为字节数组。
String str = "张三";
byte[] bytes = str.getBytes();
但是我们要将一个JavaBean对象转为字节数组的时候,我们得借助ByteArrayOutputStream流的帮助。
public static void main(String[] args) {byte[] bytes = null;ByteArrayOutputStream bos = new ByteArrayOutputStream();try{ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(obj);oos.flush();bytes = bos.toByteArray();oos.close();bos.close();} catch(IOException ex) {ex.printStackTrace();}
}
这种方式也可以很好的将JavaBean对象转为字节数组,但是代码不免有点多了!而FastJson中野提供了很方便的API以供使用。
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();//JavaBean对象转为字节数组byte[] bytes = JSON.toJSONBytes(user);
}
我们要将字节数组转为对象,FastJson也同样支持:
public static void main(String[] args) {User user = User.builder().id(1).name("张三").sex("男").age(23).build();//JavaBean对象转为字节数组byte[] bytes = JSON.toJSONBytes(user);//将字节数组转为JavaBean对象Object obj = JSON.parseObject(bytes, User.class, Feature.IgnoreNotMatch);System.out.println(obj);
}
//待更新…
相关文章:
Java 中FastJson的使用【吃透FastJson】
如果不了解JSON格式,建议先看下:JSON数据格式【学习记录】 JSON序列化、反序列化JavaBean的框架有很多,最常见的Jackson、阿里巴巴开源的FastJson、谷歌的GSON、apache提供的json-lib等,下面我们主要来熟悉一下:Java语…...
Redis5.0集群搭建
Redis集群教程 此文重在介绍 Redis5.0 三主三从集群安装,无复杂难懂的概念,若想深入了解集群原理请参考Redis集群规范。 Redis集群介绍 Redis Cluster 提供一种 Redis 安装方式:数据自动在多个 Redis 节点间分片。 Redis Cluster 提供一定…...
继企业级信息系统开发学习1.1 —— Spring配置文件管理Bean
骑士救美计划采用构造方法注入属性值1、创建救美任务类2、创建救美骑士类2、创建救美骑士类3、创建旧救美骑士测试类3、配置救美骑士Bean5、创建新救美骑士测试类采用构造方法注入属性值 1、创建救美任务类 在net.huawei.spring.day01包里创建RescueDamselQuest类 Rescue Da…...
Web 容器、HTTP 服务器 、Servlet 容器区别与联系
首先浏览器发起 HTTP 请求,像早期的时候只会请求一些静态资源,这时候需要一个服务器来处理 HTTP 请求,并且将相应的静态资源返回。 这个服务器叫 HTTP 服务器。 简单点说就是解析请求,然后得知需要服务器上面哪个文件夹下哪个名字…...
eBPF 进阶: 内核新特性进展一览
Linux 内核在 2022 年主要发布了 5.16-5.19 以及 6.0 和 6.1 这几个版本,每个版本都为 eBPF 引入了大量的新特性。本文将对这些新特性进行一点简要的介绍,更详细的资料请参考对应的链接信息。总体而言,eBPF 在内核中依然是最活跃的模块之一&a…...
2.输入子系统学习-multi-touch-protocol-2023.02
Documentation/input/multi-touch-protocol.txt(百度翻译) Multi-touch (MT) Protocol ------------------------- Copyright (C) 2009-2010 Henrik Rydberg <rydbergeuromail.se> 一、Introduction ------------ In order to utilize t…...
【靶机】vulnhub靶机pylington
靶机下载地址 Pylington: 1 ~ VulnHub kali ip:192.168.174.128 靶机ip:192.168.174.146 arp-scan -l发现靶机ip是192.168.174.146 进行靶机的端口扫描,这里使用的是nmap的gui 可以发现开放了21和80端口,80端口扫描到了robot…...
【大数据】大数据学习路线
职位选择 首先明确一点:大数据涉及的知识面广度还是有的,需要学习的组件繁多,想要每一项精通几乎不可能,所以企业在招聘的时候会进行细分,基于某个方向进行招聘,比如关键字,数据仓库工程师、数…...
【Python爬虫案例教学】采集某网站壁纸,实现壁纸自由
前言 (。・∀・)ノ゙嗨 大家好,这里是小圆 现在开始每天都给大家 分享些关于python爬虫的案例教学 从最简单的开始 — 采集图片壁纸 今天就来扒拉这个优质的壁纸网站~ 网址 👇 顺便瞧一眼 这里的…...
波卡2022年第四季度报告
本文将介绍Messari最新发布的波卡Polkadot 2022年第四季度报告内容。 1 Messari已经发布关于波卡Polkadot最新的报告:显示了2022年第四季度的日活账户增加了64%,新用户增长49%。 2 Messari指出,波卡中继链在2022第四季度的环比增长令人印象…...
第一章:初始化react项目+antd+less
初始化react项目 我们首先使用react脚手架创建一个项目 Ant Design less creact-react-app中文文档 creact-react-app demo生产环境打包运行 当我们执行了 npm run build 打包后直接访问index.html 看效果白屏 这时候就需要安装一个serve包 npm install -g serve当我们安…...
图的基本概念
1、图的概念 G(V,E) 图G由节点集合VV(G)和边集合EE(G)组成,其中V为非空有限集合。 集合V中的节点(node)用红色标出,通过集合E中黑色的边(edge)连接。 G的边:E中的每个顶点对&#x…...
MySQL必会四大函数-窗口函数
在了解窗口函数之前,我们必须了解聚合函数。常见的聚合函数,包括 AVG、COUNT、MAX、MIN、SUM 以及 GROUP_CONCAT,常和GROUP BY 函数一起使用。聚合函数的作用就是对一组数据行进行汇总计算,并且返回单个分析结果。 窗口函数和聚合…...
各CCF期刊点评网站/学术论坛的信息汇总及个人评价
CCF中文期刊投稿选择之篇章一:各CCF期刊点评网站/学术论坛的信息汇总及个人评价中文科技期刊A类(EI检索)中文期刊投稿点评网站整理1.小木虫学术论坛2. Letpub3. Justscience4. 发表记5. 会伴(Conference Partner)6. ijouranl7. 掌桥科研这是以…...
深度解析 JavaScript 严格模式:利弊长远的考量
前言 ECMAScript 5首次引入严格模式的概念。严格模式用于选择以更严格的条件检查JavaScript代码错误,可以应用到全局,也可以应用到函数内部。 严格模式的好处是可以提早发现错误,因此可以捕获某些 ECMAScript 问题导致的编程错误。 理解严格…...
Vue.js 循环语句
Vue.js 循环语句 在Vue开发中,for循环是我们最常遇见的场景之一,我们知道常见的遍历方式有for循环,for of、forEach、for in.虽然在开发过程中,这几种方式基本上可以满足我们大多数的场景,但是你真的知道他们之间的区…...
家政服务小程序实战教程12-详情页
我们的家政服务小程序已经完成了首页和分类展示页面的开发,接下来就需要开发详情页了。在详情页里我们展示我们的各项服务内容,让用户可以了解每项家政服务可以提供的内容。 低码开发不像传统开发,如果开发详情页需要考虑每个字段的类型&…...
十四、平衡二叉树
1、看一个案例(说明二叉排序树可能的问题) 给你一个数列{1,2,3,4,5,6},要求创建一棵二叉排序树(BST),并分析问题所在。 上面二叉排序树存在问题分析: 左子树全部为空,从形式上看&…...
AC/DC 基础
一、概念: AC转换成DC的基本方法有变压器方式和开关方式,如下图1、2所示;整流的基本方法有全波整流和半波整流,如下图3所示。 图1 变压器方式 图2 开关方式 图3 整流方式 二、转换方式 1、变压器方式 变压器方式首先需要通过变压…...
集成电路相关书籍
注:从此开始,文中提到的书籍都会在公众号对应文章末尾给出链接,不需要在微信后台获取,当然还是可以通过在微信后台回复相关书名获取对应的电子书。 在后台看到很多人回复集成电路相关的一些书籍,所以本文就提供一些书籍…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
