JAVA重要知识点
序列化和反序列化
定义
序列化:把数据结构或对象转换成二进制字节流
反序列化:在序列化过程中所生成的二进制字节流转换成数据结构或对象
Java是面向对象编程语言,序列化的对象是实例化后的类;在C++的半面向对象语言中,结构体定义的是数据结构类型,而类对应的是对象类型。
常见应用场景
1、对象在进行网络传输
2、将对象存储到文件
3、将对象存储到数据库(例如:Redis)
4、将对象存储到内存
常用的序列化协议
Hessian、Kryo、Protobuf、ProtoStuff,这些都是基于二进制的序列化协议。
JDK 自带的序列化方式
只需要实现java.io.Serializable接口即可
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
@ToString
public class RpcRequest implements Serializable {
private static final long serialVersionUID =
1905122041950251207L;
private String requestId;
private String interfaceName;
private String methodName;
private Object[] parameters;
private Class<?>[] paramTypes;
private RpcMessageTypeEnum rpcMessageTypeEnum;
}
serialVersionUID 的作用
中文叫做序列化号。作用是版本控制。
反序列化时,会检查这个UID是否和当前类的UID一致,如果UID不一致会抛出InvalidClassException 异常。如果不手动指定,那么编译器会动态生成默认的UID。
虽然UID被static修饰,但是“序列化”假象:static修饰的是静态变量,位于方法区,本身不会被序列化。static修饰的变量属于类,而不是对象。反序列化后,static变量的值就像是默认赋予了对象一样,是假象。
不进行序列化的字段
用transient修饰
作用:阻止实例中那些用此关键字修饰的变量序列化;当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。
注意:
- 只能修饰变量,不能修饰类和方法
- 修饰的变量,在反序列化后变量值会被置成类型的默认值
不推荐JDK自带的序列化
1、不支持跨语言调用
如果调用的是其他语言开发的服务就不支持
2、性能差
序列化后的字节数组,体积较大,传输成本高
3、存在安全问题
输入的反序列化的数据可以被用户控制。容易被攻击
Kryo
高性能的序列化工具,变长存储特性并使用了字节码生成机制,拥有较高的运行速度和较小的字节码体积。
是一种成熟的序列化实现,在开源项目中广泛使用。
Protobuf
出自Google,支持多种语言,同是是跨平台的。使用过程较为繁琐,需要自己定义IDL文件,生成对应的序列化代码。优点:没有序列化漏洞的风险
Protobuf包含序列化格式的定义,各种语言的库,IDL编译器。
用法:定义proto文件,使用IDL编译器编译成我需要的语言
ProtoStuff
基于Protobuf,提供更多的功能和更简易的用法
Hessian
轻量级,自定义描述的二进制RPC协议。跨语言的。