从比特理解Json序列化方式
关于Json 可以说是web 开发不管是前端还是后端都是非常的熟悉,第一次接触Json,是在我大一的寒假,因为人生中第一个servlet原生项目中要使用所以进行了较为粗浅的研究:
当时乃至之后的很长一段时间的理解都是——json 就是前后端数据传输的一个约定的消息格式,这种消息格式因为前后端都支持,并且是一种规范,所以我可以将对象直接转为一个Json 字符串,然后写入到返回给前端的响应流中,但是其实并不理解为什么要这样做,只是了解到前后端对接可以这样做。
当仔细研究了协议和如何解析协议之后对这部分内容有了更深层次的认知
1、什么是序列化算法?
json 是一种序列化的算法,那么说回来了,什么是序列化算法?
序列化和反序列本质上就是对象和字节数组的转换:
- 序列化时,将Java对象编码为byte数组
- 反序列化,则是将byte数组转换为Java对象
2、为什么要使用序列化算法?
很多刚入门的同学都会对比特,字节,乃至字比较反感,对01代码和十六进制都觉得非常的不熟悉,进而心生畏惧,认为字符串比字节数组方便的多,可读性也非常高,为什么不能用字符串来进行交流,而总有地方都要使用讨厌的字节。
2.1为什么要用二进制,八进制,十六进制?
对于计算机的底层来说,cpu上运行的都是01二进制的指令,而内存和磁盘中存储的数据也是二进制的,这是由于二进制本身的稳定性而决定的,简单来说就是计算机中的模拟信号数据波形并不是理想的高低有致的,更多的是处于不停波动的状态(可以理解成是极值不断变化的sin函数),这就会导致将波形转换为可操作的数字信号的时候就会非常困难,针对这样的波形特征如果再进行分段比如说xxx频到xxx频是2,xx频到xx频是3,显然是非常不易的,但是如果只区分为高低两种信号就很容易去定义信息,这就是二进制的稳定性。
实际的波形:
理想的波形:
而一个二极管能表示一位二进制,两个就是两位,八个就是八位,显然用很多个00001111101不容易去表示数据,而用可读性比较好的8进制和十六进制相对来说就更容易表示了,如果说为什么不用十进制,因为十进制不是2的整数次
2.2为什么要用字节数组
在计算机的计算和数据存储中都是用的01比特,那么在计算机网络的通信中最底层显然也是通过比特流进行数据传输的。而OSI计网架构来说,数据传输的单位显然是对比特又进行了一次封装,也就是字节。
计算机网络中运输层(为我们的数据传输提供可靠服务的一层,在计算机的网卡中集成)的传输单位是字节,而我们做网络编程其实就是在面向Socket(运输层数据传输的门户,端点)进行数据的传输,将数据转换为字节流交给网卡中集成好的运输层协议,然后运输层就会通过网络将我们的数据送到到目的地址,从应用层的角度看这一过程就是将http 请求报文转换为字节数组传递给socket,然后得到响应的字节数组,并将字节数组转换为http响应报文
2.3这和序列化算法有什么关系?
序列化就是将对象转换为字节数组,而在网络编程中传输的就是字节数组,配置序列化算法就是通过将对象转换为字节然后作为数据信息进行传递。
2.4序列化算法和协议有什么关系
我们都知道Http协议分为三部分:行,头,体,在行和头中放置的是协议的控制信息,而在体中放置的是数据的传输信息,而http协议同时也支持将传输的数据信息放到行中,也就是url 中进行数据的传输,但真正的数据传输往往都是在体中进行传输的,这就说到了网络协议制定的一个核心思想:协议头部(控制信息部分)和 数据部分
也就是说:将协议的控制信息都放到头部,将协议的数据内容都放到数据部分,而对于下面的http 协议来说,行和头其实就是协议头部,而体则是数据部分,而已经使用过json的同学,不管是用的servlet 原生的request.getOutpuStream 进行写入,还是springmvc @ResponseBody ,其实都是将对象转换为字节数组。其实都是写入到http协议的数据部分,也就是请求体和响应体中 。
也就说:在我们简单使用的网络编程中的序列化算法就是将对象编码为字节数组,然后将字节数组写入到http协议体中,这就是序列化算法在协议中应用的本质
3、集成常用的序列化算法:
- Jdk
- 要求被解析的对象实现Serializable接口
- json
- 需要导入谷歌的Gson依赖
- 常见的json解析还有fastJson和Jackjson
package d6;
import com.google.gson.Gson;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* @author: Jeffrey
* @date: 2022/01/26/8:56
* @description: 应用于编解码器
*/
public interface Serializer {
/**
* 反序列化
* @param clazz 目的参数的类对象
* @param bytes 字节数组
* @param <T> 目的对象的泛型
* @return 目的对象
*/
<T> T deSerializer(Class<T> clazz,byte[] bytes);
/**
* 序列化方法
* @param t 对象
* @param <T> 泛型
* @return 字节数组
*/
<T> byte[] serializer(T t);
enum Algorithm implements Serializer{
Jdk{
@Override
public <T> T deSerializer(Class<T> clazz, byte[] bytes) {
try {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException exception) {
throw new RuntimeException("反序列化失败");
}
}
@Override
public <T> byte[] serializer(T t) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(t);
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("序列化失败");
}
}
},
Json{
@Override
public <T> T deSerializer(Class<T> clazz, byte[] bytes) {
String json = new String(bytes, StandardCharsets.UTF_8);
return new Gson().fromJson(json,clazz);
}
@Override
public <T> byte[] serializer(T t) {
String json = new Gson().toJson(t);
return json.getBytes(StandardCharsets.UTF_8);
}
}
}
}
4、Json的语法和使用
参考博客: