一、序列化与反序列化

序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转化成二进制的过程。

即将对象转化为二进制,用于保存,或者网络传输。
反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程

与序列化相反,将二进制转化成对象。

二、序列化的作用

① 想把内存中的对象保存到一个文件中或者数据库中时候;
② 想用套接字在网络上传送对象的时候;
③ 想通过RMI传输对象的时候

一些应用场景,涉及到将对象转化成二进制,序列化保证了能够成功读取到保存的对象。

三、java的序列化实现

要实现对象的序列化,最直接的操作就是实现Serializable接口
首先创建一个对象,并实现Serializable接口:

import java.io.Serializable;public class User implements Serializable{private static final long serialVersionUID = 1L;private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User [name=" + name + ", age=" + age + "]";}}

用对象流写一个保存对象与读取对象的工具类:

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class SerializeUtil {// 保存对象,序列化public static void saveObject(Object object) throws Exception {ObjectOutputStream out = null;FileOutputStream fout = null;try {fout = new FileOutputStream("D:/1.txt");out = new ObjectOutputStream(fout);out.writeObject(object);} finally {fout.close();out.close();}}// 读取对象,反序列化public static Object readObject() throws Exception {ObjectInputStream in = null;FileInputStream fin = null;try {fin = new FileInputStream("D:/1.txt");in = new ObjectInputStream(fin);Object object = in.readObject();return object;} finally {fin.close();in.close();}}}

测试:

public class Main {public static void main(String[] args) {User user = new User();user.setName("旭旭宝宝");user.setAge(33);// 保存try {SerializeUtil.saveObject(user);} catch (Exception e) {System.out.println("保存时异常:" + e.getMessage());}// 读取User userObject;try {userObject = (User) SerializeUtil.readObject();System.out.println(userObject);} catch (Exception e) {System.out.println("读取时异常:" + e.getMessage());}}}

存入redis中的数据为什么要序列化

使用IO流中的对象流可以实现序列化操作,将对象保存到文件,再读取出来。
任何存储都需要序列化。只不过常规你在用DB一类存储的时候,这个事情DB帮你在内部搞定了(直接把SQL带有类型的数据转换成内部序列化的格式,存储;读取时再解析出来)。而Redis并不会帮你做这个事情。当你用Redis的key和value时,value对于redis来讲就是个byte array。你要自己负责把你的数据结构转换成byte array,等读取时再读出来。一个特例是字符串,因为字符串自己几乎就已经是byte array了,所以不需要自己处理。因此当你要用redis存一个东西,你可能会遇到如果是boolean类型的true/false;你要自己定义redis里怎么表示true和false。比如你可以用1代表true,0代表false;也可以用“true”这个字符串代表true,“false”这个字符串代表false。如果是数字,可以直接存储数字的字符串表示(5 –> ‘5’),然后读取时再把数字字符串转回来(parseInt/parseDouble/…)。如果是时间/日期,可以自己定义一种字符串表达,比如epoc timestamp这个数的字符串表示,又或者是ISO8601的格式。如果是一个复杂的数据结构,你需要自己用某种序列化格式来存,可以是json, protobuf, avro, java serialization, python pickle……回到Spring这边。Spring的redisTemplate默认会使用java serialization做序列化。你也可以用StringRedisTemplate,那么你set的所有数据都会被toString一下再存到redis里。但这个toString不一定能反解析的回来……总之简单一句话,你要形成一个序列化的约定,确保存进去的东西能解析回来不出错。也许你可以和你的team商量一个规范。