目录
一、是什么
序列化(Serialization)
是将数据结构或对象转换成一种可存储或可传输格式的过程。在序列化后,数据可以被写入文件、发送到网络或存储在数据库中,以便在需要时可以再次还原成原始的数据结构或对象。序列化的过程通常涉及将数据转换成字节流或类似的格式,使其能够在不同平台和编程语言之间进行传输和交换。
反序列化(Deserialization)
是序列化的逆过程,即将序列化后的数据重新还原成原始的数据结构或对象。反序列化是从文件、网络数据或数据库中读取序列化的数据,并将其转换回原始形式,以便在程序中进行使用和操作。
二、使用场景
- 数据存储:将程序中的数据保存到文件或数据库中,以便在以后重新加载和使用。
- 网络通信:在网络上传输数据时,需要将数据序列化为字节流,以便在接收端进行反序列化。
- 分布式系统:在分布式系统中,不同计算节点之间需要通过序列化和反序列化来交换数据。
- 进程间通信:不同进程之间通信时,数据需要在序列化和反序列化之间进行转换。
- 常见的序列化格式包括 JSON(JavaScript Object Notation)、XML(eXtensible Markup Language)、Protocol Buffers、MessagePack等。每种格式有其优势和适用场景,选择合适的序列化格式取决于具体的应用需求。
三、框架
XML 序列化框架介绍
XML 序列化的好处在于可读性好,方便阅读和调试。但是序列化以后的字节码文件比较大, 而且效率不高,适用于对性能不高。
JSON 序列化框架
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相对于XML来说,JSON 的字节流更小,而且可读性也非常好。现在JSON数据格式在企业运用是最普遍的 JSON序列化常用的开源工具有很多,如:
- Jackson
- 阿里开源的FastJson
四、问题
父类实现了序列化,子类需不需要实现序列化?反过来子类需要实现序列化,父类要不要实现序列化?
- 父类实现了序列化,则子类自动实现了序列化,即子类不需要显式实现Serializable接口,子类构造时会递归调用父类构造。
- 当父类没有实现序列化,而子类需要实现时,子类需要显式实现Serializable接口,并且父类中需要有无参的构造函数。
序列化保存的是对象还是方法?
- 序列化时,只对对象的状态进行保存,而不管对象的方法。
但是并非所有的对象都可以序列化,比如:
- 安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
- 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。
注意
- 当类中的实例变量引用了其他对象,那么在对该类进行序列化时,引用的对象也会被序列化(需要这个引用的对象也实现Serializable接口,否则会出java.io.NotSerializableException)
- 静态成员变量属于类不属于对象,所以不参与序列化过程。
- 用transient关键字标记的成员变量不参与序列化过程。
五、Jackson 枚举反序列化器
/*
@Slf4j:这是 Lombok 提供的注解,用于自动生成一个名为 log 的日志记录器。你可以通过这个记录器来打印日志信息。
@Setter:Lombok 提供的另一个注解,自动为类中的属性生成 setter 方法。
@JsonComponent:这是 Jackson 提供的注解,表明该类是一个 JSON 组件,可以被 Jackson 管理。
*/
@Slf4j
@Setter
@JsonComponent
public class JacksonEnumDeserializer extends JsonDeserializer<Enum<?>> implements ContextualDeserializer {
private Class<?> clazz;//用于存储待反序列化的枚举的 Class 对象。
/**
* 反序列化操作
*
* @param jsonParser
* json 解析器
*
* @param ctx
* 反序列化上下文
*
* @return 反序列化后的枚举值
* @throws IOException 反序列化异常
*/
@Override
// 定义一个枚举类型,需要使用 enum 关键字,后面跟着枚举类型的名称,
public Enum<?>deserialize(JsonParser jsonParser, DeserializationContext ctx)throws IOException {
Class<?>enumType = clazz;
if(Objects.isNull(enumType)||enumType.isEnum()){
return null;
}
//读取 JSON 中的文本值 text。
String text = jsonParser.getText();
//遍历枚举常量,使用 StringToEnumConverterFactory 中的方法转换字符串值,判断是否与 text 相匹配。如果找到匹配的枚举值,则返回该枚举对象。
Method[] method = StringToEnumConverterFactory.getMethod(clazz);
Enum<?>[] enumConstants = (Enum<?>[]) enumType.getEnumConstants();
for (Enum<?> e : enumConstants) {
try{
if(Objects.equals(method.invoke(e).toString(),text)){
return e;
}
}catch (IllegalAccessException | InvocationTargetException ex){
log.error("获取枚举值错误",ex);
}
}
return null;
}
/**
* 为不同的枚举获取合适的解析器
*
* @param ctx
* 反序列化上下文
*
* @param property
* property
*/
@Override
public JsonDeserializer<Enum<?>> createContextual(DeserializationContext ctx, BeanProperty property){
//从上下文中获取要反序列化的枚举的原始类 rawCls。
Class<?>rawCls = ctx.getContextualType().getRawClass();
// 创建一个新的 JacksonEnumDeserializer 实例,并设置其 clazz 属性为 rawCls。
JacksonEnumDeserializer converter = new JacksonEnumDeserializer();
converter.setClazz(rawCls);
return converter;
}
}
标签:对象,子类,ctx,JSON,枚举,序列化 From: https://blog.csdn.net/liiilbb/article/details/143692183