一文讲透Java序列化

一、序列化是什么

二、为什么需要序列化

三、序列化怎么用

四、序列化深度探秘

4.1 为什么必须实现Serializable接口

4.2 被序列化对象的字段是引用时该怎么办 

4.3 同一个对象会被序列化多次吗

4.4 只想序列化对象的部分字段该怎么办

4.5 被序列化对象具有继承关系该怎么办

五、serialVersionUID的作用及自动生成

六、序列化的缺点

七、参考文献

 

前言

 

Oracle 公司计划废除 Java 中的古董:序列化技术,因为它带来了许多严重的安全问题(如序列化存储安全、反序列化安全、传输安全等),据统计,至少有3分之1的漏洞是序列化带来的,这也是 1997 年诞生序列化技术的一个巨大错误。但是,序列化技术现在在 Java 应用中无处不在,特别是现在的持久化框架和分布式技术中,都需要利用序列化来传输对象,如:Hibernate、Mybatis、Java RMI、Dubbo等,即对象要存储或者传输都不可避免要用到序列化技术,所以删除序列化技术将是一个长期的计划。

 

你在实际工作中可能会很难有机会真正用到Java自带的序列化技术了,工业界一般也会选择一些更安全的对象编解码方案例如Google的Protobuf等。所以,对于Java序列化,我们不必再投入过多的精力学习,你花20分钟读完本文所掌握的知识,对于应付日常源码阅读中遇到的遗留的Java序列化技术应该是足够了。

 

一、序列化是什么

 

序列化机制允许将实现序列化的Java对象转换成字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以备以后重新恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。

序列化:将一个Java对象写入IO流中

反序列化:从IO流中恢复该Java对象

 

本文中用序列化来简称整个序列化和反序列化机制。 

 

二、为什么需要序列化

 

所有可能在网络上传输的对象的类都应该是可序列化的,否则程序将会出现异常,比如RMI(Remote Method Invoke,即远程方法调用,是JavaEE的基础)过程中的参数和返回值;所有需要保存到磁盘里的对象的类都必须可序列化,比如Web应用中需要保存到HttpSession或ServletContext属性的Java对象。

 

因为序列化是RMI过程的参数和返回值都必须实现的机制,而RMI又是Java EE技术的基础——所有的分布式应用常常需要跨平台、跨网络,所以要求所有传递的参数、返回值必须实现序列化。因此序列化机制是Java EE平台的基础。通常建议:程序创建的每个JavaBean类都实现Serializable。

 

三、序列化怎么用

 

如果一个类的对象需要序列化,那么在Java语法层面,这个类需要:

实现Serializable接口

使用ObjectOutputStream将对象输出到流,实现对象的序列化;使用ObjectInputStream从流中读取对象,实现对象的反序列化

 

下面我们通过代码示例来看看序列化最基本的用法。我们创建了Person类,其拥有两个基本类型的属性,并实现了Serializable接口。testSerialize方法用来测试序列化,testDeserialize方法用来测试反序列化。

1 import org.junit.Test; 2 3 import java.io.*; 4 5 public class SerializableTest { 6 7 @Test 8 public void testSerialize() { 9 Person one = new Person(12, 148.2); 10 Person two = new Person(35, 177.8); 11 12 try (ObjectOutputStream output = 13 new ObjectOutputStream(new FileOutputStream("Person.txt"))) { 14 output.writeObject(one); 15 output.writeObject(two); 16 } catch (IOException e) { 17 e.printStackTrace(); 18 } 19 } 20 21 @Test 22 public void testDeserialize() { 23 24 try (ObjectInputStream input = 25 new ObjectInputStream(new FileInputStream("Person.txt"))) { 26 Person one = (Person) input.readObject(); 27 Person two = (Person) input.readObject(); 28 29 System.out.println(one); 30 System.out.println(two); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } catch (ClassNotFoundException e) { 34 e.printStackTrace(); 35 } 36 } 37 } 38 39 class Person implements Serializable { 40 int age; 41 double height; 42 43 public Person(int age, double height) { 44 this.age = age; 45 this.height = height; 46 } 47 48 @Override 49 public String toString() { 50 return "Person{" + 51 "age=" + age + 52 ",color: rgba(0, 128, 128, 1)">53 '}'; 54 } 55 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgfjzs.html