一、序列化与反序列化
1.1、java的序列化与反序列化
- 对象的序列化:把对象转换为字节序列的过程
- 对象的反序列化:把字节序列恢复为对象的过程
1.2、对象的序列化主要有两种用途:
- 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
- 在网络上传送对象的字节序列。
1.3、其他序列化形式
- json和xml都属于序列化,java的序列化适用于远程rpc接口,双方都是使用java对象进行交互。像web接口,与前端进行交互的,需要使用其他方式的序列化。
二、java序列化
- 对象有行为和属性两种状态,将对象的(行为和状态)转成成字节的形式保存入文件中,然后在网络中传输。获取该文件对象的,将其字节写入字节程序代码中,然后解析出对应的对象(包括状态和行为)
2.1、将序列化对象写入文件
- 创建文件FileOutputStream,将字节写入文件
FileOutputStream fileSream = new FileOutputStream("myFile.ser")
- 创建对象ObjectOutputStream,把对象转换成可以写入串流的数据
ObjectOutputStream os = new ObjectOutputStream(fileSream)
- 写入对象。对象会被打成串流送到FileOutputStream
os.writeObject(character1)
os.writeObject(character2)
os.writeObject(character3)
- 关闭文件
os.close()
2.2、注意点
- 保存了实例变量和类的信息
- 当对象被序列化时,被该对象引用的实例变量也会被序列化。且所有的引用都会被序列化,这样才可以在反序列化的时候完整的恢复
- 让类能够被序列化,则实现Serializable接口
- 当某个对象引用的实例变量对象没有被序列化,这个实例变量,必须定义成transient 的,这样序列化的程序会跳过它。这种实例变量的恢复有两种解决办法:1、反序列化,重新创建一个这样无状态的对象;2、反序列化,重新创建对象并赋值。
三、反序列化
3.1、将序列化对象写入文件
- 创建文件FileIutputStream,将字节写入文件
FileIutputStream fileSream = new FileIutputStream("myFile.ser")
- 创建对象ObjectIutputStream,把对象转换成可以写入串流的数据
ObjectIutputStream os = new ObjectIutputStream(fileSream)
- 写入对象。对象会被打成串流送到FileOutputStream
Object one = os.readObject(character1)
Object two = os.readObject(character2)
Object three = os.readObject(character3)
- 转换对象类型
GameObj obj1 = (GameObj)one
GameObj obj2 = (GameObj)two
GameObj obj3 = (GameObj)three
- 关闭文件
os.close()
3.2、解序列化过程
- 对象从stream中读出来
- java虚拟机通过存储的信息(包含实例变量信息和类的信息)判断出对象的class类型
- java虚拟机尝试寻找和加载对象的类;若java虚拟机找不到或无法加载该类,则java虚拟机会抛出异常
- 新的对象会被配置在堆上,但是不会执行构造函数(因为执行构造函数会把对象的状态全部抹去)
- 对象的实例变量会被还原成序列化时点的状态值。transient变量会被赋值为null的对象引用或primitive主数据类型默认的0、false等值。
- static静态变量,不会被序列化。static变量,是类的所有实例公用一份
四、文件的写入和读出
4.1、将字符串写入文件
FileWriter writer = new FileWriter("myFlie.txt");
writer.write("hello hshs");//直接对磁盘进行的操作
writer.close();
4.2、缓冲区的方式写入
- 将文件分次写入缓冲区,达到一定量一次性写入磁盘,这样可以减少对磁盘操作的次数,可以提高性能。
BufferedWriter writer = new Buffered( new FileWriter("myFile.txt"));
writer.flush();//要求缓冲区的内容写入磁盘中。
4.3、文件的写入
File myFile = new File("myText.txt")//file对象代表的文件的路径,而不是文件本身
FileReader fileReader = new FileReader(myFile);
BufferedReader reader = new BuferedReader(fileReader);
String line = null;
while(line = reader.readLine() != null){
System.out.println(line)
}
reader.close()
五、序列化的ID
5.1、会损坏解序列化的修改:
- 删除实例变量
- 改变实例变量的类型
- 将非瞬时的实例变量改成瞬时变量
- 改变类的继承层次
- 将类从可序列化改成不可序列化
- 将实例变量改成静态的
5.2、不会损坏解序列化的修改:
- 将瞬时变量改成非瞬时变量
- 加入新的实例变量,还原成默认值
5.3、通过序列化来控制解序列化对象是否准确
- 序列化的时候,会带上一个版本id
- 当解序列化的时候,会拿这个id与现在类对象的id进行比较,若不一致,则会解序列化失败