1、什么是序列化与反序列化?
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
2、是么时候需要序列化和反序列化
-
当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
-
当你想用套接字在网络上传送对象的时候;
-
当你想通过RMI传输对象的时候;
3、实现接口 Serializable 注意点
- 静态 static 修饰的变量不序列化
- 在实现这个Serializable 接口的时候,一定要设置 serialVersionUID 字段并且给这个 字段 赋值(一般为1L,L最好大写,小写会容易误认为11)
public class Header implements Serializable {
//实现 Serializable 接口的时候,一定要给 serialVersionUID 赋值
private static final long serialVersionUID = 1L; //静态属性不进行序列化
}
序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 “serialVersionUID” 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID。
如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java™ 对象序列化规范”中所述。
但是,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因是计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修饰符显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于直接声明类 serialVersionUID 字段作为继承成员没有用处。
数组类不能声明一个明确的 serialVersionUID,因此它们总是具有默认的计算值,但是数组类没有匹配 serialVersionUID 值的要求。
4、序列化实现
接口实现类:Header 实现 Serializable 接口
package yushi.pojo;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* netty心跳头
*
* @author leebp
* @create 2021-11-25-21:01
*/
public class Header implements Serializable {
//实现 Serializable 接口的时候,一定要给 serialVersionUID 赋值
private static final long serialVersionUID = 1L; //静态属性不进行序列化
private String RequestM = "POST /LAPI/V1.0/PACS/Controller/HeartReportInfo HTTP/1.1";
private String ContentType = "application/json";
private int ContentLength = 178;
private String RefId = "2936f461-6e79-465c-996d-f7ddb9660346"; //请求流水号
private String Time = "2020-03-18 20:13:45"; //本次心跳上报时间
private String NextTime = "2020-03-18 20:18:45"; //下次心跳上报时间
private String DeviceCode = "210235C31L3186000023"; //设备编码(设备序列号)
private byte DeviceType = 1; //设备类型 1:普通门禁; 2:可视对讲门禁; 3:考勤机; 4:录入设备; 5:室内机
//private Map<String, Object> attachment = new HashMap<>();
public String getRequestM() {
return RequestM;
}
public void setRequestM(String RequestM) {
this.RequestM = RequestM;
}
public String getContentType() {
return ContentType;
}
public void setContentType(String contentType) {
ContentType = contentType;
}
public int getContentLength() {
return ContentLength;
}
public void setContentLength(int contentLength) {
ContentLength = contentLength;
}
public String getRefId() {
return RefId;
}
public void setRefId(String refId) {
RefId = refId;
}
public String getTime() {
return Time;
}
public void setTime(String time) {
Time = time;
}
public String getNextTime() {
return NextTime;
}
public void setNextTime(String nextTime) {
NextTime = nextTime;
}
public String getDeviceCode() {
return DeviceCode;
}
public void setDeviceCode(String deviceCode) {
DeviceCode = deviceCode;
}
public byte getDeviceType() {
return DeviceType;
}
public void setDeviceType(byte deviceType) {
DeviceType = deviceType;
}
@Override
public String toString() {
return "Header{" +
"RequestM='" + RequestM + '\'' +
", ContentType='" + ContentType + '\'' +
", ContentLength=" + ContentLength +
", RefId='" + RefId + '\'' +
", Time='" + Time + '\'' +
", NextTime='" + NextTime + '\'' +
", DeviceCode='" + DeviceCode + '\'' +
", DeviceType=" + DeviceType +
'}';
}
}
序列化工具类:实现序列化和反序列化
package yushi.utils;
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 序列化工具
*
* @author leebp
* @create 2021-11-25-20:41
*/
public class SerializationUtil {
private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();
private static Objenesis objenesis = new ObjenesisStd(true);
private static <T> Schema<T> getSchema(Class<T> clazz) {
@SuppressWarnings("unchecked")
Schema<T> schema = (Schema<T>)cachedSchema.get(clazz);
if (schema == null) {
schema = RuntimeSchema.getSchema(clazz);
if (schema != null) {
cachedSchema.put(clazz, schema);
}
}
return schema;
}
/**
* 序列化
*
* @param obj
* @return
*/
public static <T> byte[] serializer(T obj) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>)obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema<T> schema = getSchema(clazz);
byte result[] = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
return result;
}
catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
finally {
buffer.clear();
}
}
/**
* 反序列化
*
* @param data
* @param clazz
* @return
*/
public static <T> T deserializer(byte[] data, Class<T> clazz) {
try {
T obj = objenesis.newInstance(clazz);
Schema<T> schema = getSchema(clazz);
ProtostuffIOUtil.mergeFrom(data, obj, schema);
return obj;
}
catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
调用 SerializationUtil中的 serializer() 和 deserializer() 方法:
//对输入数据 in(对象Object) 序列化后存储在 data(字节序列) 数组中
byte[] data = SerializationUtil.serializer(in); //序列化:对象-->字节序列
//对输入数据 data(字节序列) 反序列化后存储在 obj(对象) 中
Object obj = SerializationUtil.deserializer(data, genericClass);//反序列化:字节序列-->对象
【注】:
上述代码并不完整,仅供参考!