【Java学习笔记】对象的序列化和反序列化

简介: 作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.定义: 序列化,也叫串行化--将对象写到一个输出流(一般是一个文件)中。反序列化则是从一个输入流中读取一个对象。

作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/

1.定义:

序列化,也叫串行化--将对象写到一个输出流(一般是一个文件)中。反序列化则是从一个输入流中读取一个对象。类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能被序列化和反序列化。这个接口是一个表示型的接口。serialVersionUID 是一个串行化类的通用标示符,反串行化就是使用这个标示符确保一个加载的类对应一个可串行化的对象。

若自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法可以用。serialVersionUID的生成,可以写1,也可以写2,但最好还是按照摘要算法,生成一个惟一的指纹数字,eclipse可以自动生成的,jdk也自带了这个工具。一般写法类似于
private static final long serialVersionUID = -763618247875550322L;

 

简单的使用请参加我的另一篇习作:http://blog.csdn.net/gnuhpc/archive/2009/08/01/4396149.aspx

 

2.序列化步骤:

1)创建一个对象输出流:可以包装一个其他类型的输出流。

2)通过对象输出流的writeObject()写对象。注意使用类型转化,转换为相应的类的对象。

3.反序列化步骤:

1)创建一个对象输入流:可以包装一个其他类型的输出流。

2)通过对象输出流的readObject()写对象。

4.什么对象需要被序列化?

序列化的基本想法是完成对实例信息的保证。因为实例信息在运行结束后就消失了。要储存什么信息呢?一定不是关于方法的信息。

 

5.使用注意事项:

a.有些属性处于安全考虑不能被序列化(或者不能被序列化,比如Thread),则用transit修饰,若想进一步控制序列化和反序列化,则类中提供readObject()方法和writeObject()方法,(反)序列化时就会调用自定义的方法。注意这两个方法不是在java.io.Serializable接口定义的,而是在ObjectInputStream和ObjectOutputStream类中定义的,这两个类实现ObjectInput 和ObjectOutput两个接口。下边是一个可变数组的例子,取自Java in a Nutshell 2rd Edition,它在串行化实现了高效的针对可变数组程度调整的方法:

 

b.由于串行化是针对类的实例,也就是对象的,所以static这样的成员是类相关的,也就不会被串行化。
c.注意,API中一个类一旦被串行化了,那么它的父类都是串行化的。你自己设计的类要是想被串行化,那么其父类要确保都串行化。父类一旦串行化,则子类们都自动实现了串行化。所以内部类和可扩展类不建议串行化。

d. 若想加密序列化的数据,可以重写writeObject和readObject,并将加密算法写入其中,最后调用stream.defaultWriteObject();或者stream.defaultReadObject();实现模糊化——当然,你若是想在序列化和反序列化前后执行任何操作都可以在这里定制,比如,这个类的父类实现了串行化,但你并不希望这个类可以被串行化,那么就可以在串行化和反串行化的时候抛出异常:

 

 

 

如果需要对整个对象进行加密和签名,最简单的是将它放在一个 javax.crypto.SealedObject 和/或 java.security.SignedObject 包装器中。两者都是可序列化的,所以将对象包装在 SealedObject 中可以围绕原对象创建一种 “包装盒”。必须有对称密钥才能解密,而且密钥必须单独管理。同样,也可以将 SignedObject 用于数据验证,并且对称密钥也必须单独管理。

e.序列化不是针对的对象的文件和方法,而是对象的状态,因此在反序列化时对象的类文件必须存在。

f.若想创建自己的串行化方式请实现Externalizable接口,而不是Serializable接口,重写下边两个方法:

 

public void writeExternal(ObjectOutput out) throws IOException;

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;

注意这里你没有了默认的动作可以做,一切都要靠自己。除此之外这个接口与串行化接口没有区别。默认的串行化方法可能会带来时间开销,若你想优化的话,不妨从自定义简单串行化方法开始。这个接口的实际用途在于若你想串行化父类的数据成员,那么依靠原始的串行化接口是无法满足的,你必须自定义串行化方法:

[java:nogutter] view plain copy
  1. import java.io.*; 
  2. public class TestExternalizable 
  3. FileOutputStream fout = null
  4. ObjectOutputStream objOut = null
  5.  public TestExternalizable() { 
  6.  try
  7.    TestSub testSub = new TestSub(); 
  8.    testSub.setName(NAME); 
  9.    testSub.setAge(AGE); 
  10.    fout = new FileOutputStream(FILE_NAME); 
  11.    objOut = new ObjectOutputStream(fout); 
  12.    objOut.writeObject(testSub); 
  13.    objOut.flush(); 
  14.    objOut.close(); 
  15.    fout.close(); 
  16.    FileInputStream fin = new FileInputStream(FILE_NAME); 
  17.    ObjectInputStream objIn = new ObjectInputStream(fin); 
  18.    TestSub ts = (TestSub)objIn.readObject(); 
  19.    objIn.close(); 
  20.    fin.close(); 
  21.    System.out.println(ts.name+" "+ts.age); 
  22. } catch(Exception ex) { 
  23.      ex.printStackTrace(); 
  24.  public static void main(String[] args) 
  25.    new TestExternalizable(); 
  26. class TestSuper{ 
  27. String name = null
  28.  int age = 0
  29.  public void setName(String name) { 
  30.  this.name = name; 
  31.  public void setAge(int age) { 
  32.    this.age = age; 
  33.  public void readExternal(ObjectInput objectInput) { 
  34.    try
  35.      name = (String)objectInput.readObject(); 
  36.      age = objectInput.readInt(); 
  37.    } catch(Exception ex) { 
  38.      ex.printStackTrace(); 
  39.    } 
  40.  public void writeExternal(ObjectOutput objectOutput) { 
  41.    try 
  42.    { 
  43.      objectOutput.writeObject(name); 
  44.      objectOutput.writeInt(age); 
  45.    } catch (Exception ex) { 
  46.      ex.printStackTrace(); 
  47.    } 
  48. class TestSub extends TestSuper implements Externalizable { 
  49.    public TestSub() { 
  50.    } 
import java.io.*; public class TestExternalizable { FileOutputStream fout = null; ObjectOutputStream objOut = null; public TestExternalizable() { try{ TestSub testSub = new TestSub(); testSub.setName(NAME); testSub.setAge(AGE); fout = new FileOutputStream(FILE_NAME); objOut = new ObjectOutputStream(fout); objOut.writeObject(testSub); objOut.flush(); objOut.close(); fout.close(); FileInputStream fin = new FileInputStream(FILE_NAME); ObjectInputStream objIn = new ObjectInputStream(fin); TestSub ts = (TestSub)objIn.readObject(); objIn.close(); fin.close(); System.out.println(ts.name+" "+ts.age); } catch(Exception ex) { ex.printStackTrace(); } } public static void main(String[] args) { new TestExternalizable(); } } class TestSuper{ String name = null; int age = 0; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void readExternal(ObjectInput objectInput) { try{ name = (String)objectInput.readObject(); age = objectInput.readInt(); } catch(Exception ex) { ex.printStackTrace(); } } public void writeExternal(ObjectOutput objectOutput) { try { objectOutput.writeObject(name); objectOutput.writeInt(age); } catch (Exception ex) { ex.printStackTrace(); } } } class TestSub extends TestSuper implements Externalizable { public TestSub() { } }  

h.你若是在一个打开的流中写了两次,第二次是不会被保存的,若想重新写要调用ObjectOutputStream.reset() 方法。

 

作者:gnuhpc
出处:http://www.cnblogs.com/gnuhpc/


               作者:gnuhpc
               出处:http://www.cnblogs.com/gnuhpc/
               除非另有声明,本网站采用知识共享“署名 2.5 中国大陆”许可协议授权。


分享到:

目录
相关文章
|
7月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
395 1
|
7月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
366 1
|
8月前
|
Java
Java 数组学习笔记
本文整理Java数组常用操作:遍历、求和、查找、最值及二维数组行求和等典型练习,涵盖静态初始化、元素翻倍、去极值求平均等实例,帮助掌握数组基础与应用。
|
8月前
|
小程序 Java 知识图谱
Java 学习笔记 —— BMI & BMR 计算器
这是一个使用 Java 编写的 BMI 与 BMR 计算器小程序,可输入年龄、性别、身高和体重,计算身体质量指数(BMI)和基础代谢率(BMR),并输出健康评估结果。通过该项目,掌握了 Java 的输入处理、数据验证、条件判断、数学运算及格式化输出等基础知识,是 Java 初学者的理想练习项目。
|
10月前
|
存储 安全 Java
深入理解Java序列化接口及其实现机制
记住,序列化不仅仅是把对象状态保存下来那么简单,它涉及到类的版本控制、安全性和性能等多个重要方面。正确理解和实现Java序列化机制对于构建高效、安全和可维护的Java应用至关重要。
307 0
|
11月前
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
582 5
|
11月前
|
JSON 安全 Java
说一说 Java 反序列化漏洞
我是小假 期待与你的下一次相遇 ~
307 1
说一说 Java 反序列化漏洞
|
11月前
|
存储 Java 编译器
说一说关于序列化/反序列化中的细节问题
我是小假 期待与你的下一次相遇 ~
220 1
|
安全 网络协议 Java
Java反序列化漏洞与URLDNS利用链分析
Java反序列化漏洞与URLDNS利用链分析
544 4
|
存储 缓存 安全
Java安全之反序列化漏洞分析
Java安全之反序列化漏洞分析
749 0
Java安全之反序列化漏洞分析