序列化与反序列化
面对序列化与反序列化,很多人问我这个问题,是什么?用来做什么?趁着空闲,打算记录一下。
1、序列化与反序列化的概念:
序列化:把对象转换为字节序列的过程叫做对象的序列化。
反序列化:把字节序列回复为对象的过程称为对象的反序列化。
通常在代码运行的时候可以看到好多对象,而这些对象想要保存起来,比如说redis存储Map对象,那么redis中存储的这个对象是以序列化的形式保存起来,当我们需要用的时候,从redis取出,把这些字节存储的内容转成原来的对象进行展示。
2、什么情况下需要序列化
当你想把呢村的对象状态保存到某一个文件中或者数据库中【redis相当于一个数据库】
当你想用套接字在网络上传达对象的时候;
当你想通过RMI传输对象的时候;
【以上几种方式我大部分用的都是redis存对象的时候用到过】
3、如何实现序列化
实现Serializable接口
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* @author :biejie
* @date :Created in 2019/1/9 17:14
* @description:理解序列化与反序列化含义
* @modified By:
* @version: 1.0$
*/
public class OneController {
public static void main(String[] args) throws Exception {
serializeFlyPig();
Map<String,Object> TestOne = deserializeFlyPig();
System.out.println(TestOne.toString());
}
/**
* 序列化
*/
private static void serializeFlyPig() throws IOException {
Map<String,Object> map =new HashMap<>();
map.put("a","a");
map.put("fds","感觉");
map.put("584","放大");
// ObjectOutputStream 对象输出流,将 testOne 对象存储到d盘的 testOne.txt 文件中,完成对 testOne 对象的序列化操作
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/testOne.txt")));
oos.writeObject(map);
System.out.println("testOne 对象序列化成功!");
oos.close();
}
/**
* 反序列化
*/
private static Map<String,Object> deserializeFlyPig() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/testOne.txt")));
Map<String,Object> person = (Map<String, Object>) ois.readObject();
System.out.println("testOne 对象反序列化成功!");
return person;
}
}
输出结果如下:
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165552849-730830189.png)
文本打印内容:
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165605085-855389098.png)
对于上述序列化与反序列化的代码解读:
ObjectOutputStream:对象输出流
ObjectOutputStream.writeObject(Object obj):可对参数指定的obj对象进行序列化,然后把得到的字节序列写到一个目标输出流中。
ObjectInputStream:对象输入流
ObjectInputStream.readObject():从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
不要以为这样就掌握了序列化,
实体类继承 java.io.Serializable后,需要设置序列化ID,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
通俗意义上面的讲就是有一个 序列号id:serialVersionUID ,默认java会根据class计算 serialVersionUID值,它的作用是用在反序列化【检查】当前类是否被修改过,如果发现 serialVersionUID与当前对不上号,就会报异常, 那么会抛出 java.io.InvalidClassException的异常,这种情况发生在由于种种因素修改了序列化对象的类文件时。 有时候我们确实有这样的需求,我对类进行改变,但又希望反序列化的时候还是与之前版本的序列化的对象类的 serialVersionUID进行对应,那么我们只需要指定 serialVersionUID的值为某个固定值就可以了 .
看到这,我尝试了一下,发现:
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165616794-1661291945.png)
我先序列化一个有5个key-value对象,并且把字节序列存到另一个地方,![]()
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165628808-1286023634.png)
然后我再序列化一个有3个key-value对象,![]()
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165704172-1585479415.png)
然后我把test3复制到testOne文本内,然后放反序列化字段:
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165716279-1899737980.png)
执行;
![](https://img2018.cnblogs.com/blog/934616/201902/934616-20190211165724581-1083379256.png)
发现报上面的错误,瞬间感觉自己弱弱的,怎么和自己的预期不是一样的,然后找了相关资料,才知道这个问题是
意思是用ObjectInputStream反序列化读入的数据不是由ObjectOutputStream产生的。
然后我遇到了困惑,上网试了几个方法解决,都没得用,还需要众神解惑下。