`
hjy2099
  • 浏览: 255278 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Java对象的序列化和反序列化实践

    博客分类:
  • JAVA
阅读更多

引:当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

  当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

  把Java对象转换为字节序列的过程称为对象的序列化。

  把字节序列恢复为Java对象的过程称为对象的反序列化。

  对象的序列化主要有两种用途:

  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

  2) 在网络上传送对象的字节序列。

  一. JDK类库中的序列化API

  java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。、

  只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式 。

  对象序列化包括如下步骤:

  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;

  2) 通过对象输出流的writeObject()方法写对象。

  对象反序列化的步骤如下:

  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;

  2) 通过对象输入流的readObject()方法读取对象。

  下面让我们来看一个对应的例子,类的内容如下:

import java.io.*;
import java.util.Date;

/**
* 对象的序列化和反序列化测试类.
* @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
* @version 1.0
* Creation date: 2007-9-15 - 下午21:45:48
*/

public class ObjectSaver {
 /**
 * @param args
 * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
 * Creation date: 2007-9-15 - 下午21:45:37
 */

public static void main(String[] args) throws Exception {
 ObjectOutputStream out = new ObjectOutputStream
(new FileOutputStream("D:""objectFile.obj"));

 //序列化对象

 Customer customer = new Customer("阿蜜果", 24);
 out.writeObject("你好!");
 out.writeObject(new Date());
 out.writeObject(customer);
 out.writeInt(123); //写入基本类型数据
 out.close();
 //反序列化对象

 ObjectInputStream in = new ObjectInputStream
(new FileInputStream("D:""objectFile.obj"));

 System.out.println("obj1=" + (String) in.readObject());
 System.out.println("obj2=" + (Date) in.readObject());
 Customer obj3 = (Customer) in.readObject();
 System.out.println("obj3=" + obj3);
 int obj4 = in.readInt();
 System.out.println("obj4=" + obj4);
 in.close();
}
}

class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}

public String toString() {
return "name=" + name + ", age=" + age;
}
}


  输出结果如下:

obj1=你好!

obj2=Sat Sep 15 22:02:21 CST 2007

obj3=name=阿蜜果, age=24

obj4=123


  因此例比较简单,在此不再详述。

  二.实现Serializable接口

  ObjectOutputStream只能对Serializable接口的类的对象进行序列化。默认情况下,ObjectOutputStream按照默认方式序列化,这种序列化方式仅仅对对象的非transient的实例变量进行序列化,而不会序列化对象的transient的实例变量,也不会序列化静态变量。

  当ObjectOutputStream按照默认方式反序列化时,具有如下特点:

  1) 如果在内存中对象所属的类还没有被加载,那么会先加载并初始化这个类。如果在classpath中不存在相应的类文件,那么会抛出ClassNotFoundException;

  2) 在反序列化时不会调用类的任何构造方法。

  如果用户希望控制类的序列化方式,可以在可序列化类中提供以下形式的writeObject()和readObject()方法。

private void writeObject(java.io.ObjectOutputStream out) throws IOException

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;


  当ObjectOutputStream对一个Customer对象进行序列化时,如果该对象具有writeObject()方法,那么就会执行这一方法,否则就按默认方式序列化。在该对象的writeObjectt()方法中,可以先调用ObjectOutputStream的defaultWriteObject()方法,使得对象输出流先执行默认的序列化操作。同理可得出反序列化的情况,不过这次是defaultReadObject()方法。

  有些对象中包含一些敏感信息,这些信息不宜对外公开。如果按照默认方式对它们序列化,那么它们的序列化数据在网络上传输时,可能会被不法份子窃取。对于这类信息,可以对它们进行加密后再序列化,在反序列化时则需要解密,再恢复为原来的信息。

  默认的序列化方式会序列化整个对象图,这需要递归遍历对象图。如果对象图很复杂,递归遍历操作需要消耗很多的空间和时间,它的内部数据结构为双向列表。

  在应用时,如果对某些成员变量都改为transient类型,将节省空间和时间,提高序列化的性能。

  三. 实现Externalizable接口

  Externalizable接口继承自Serializable接口,如果一个类实现了Externalizable接口,那么将完全由这个类控制自身的序列化行为。Externalizable接口声明了两个方法:

public void writeExternal(ObjectOutput out) throws IOException

public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException


  前者负责序列化操作,后者负责反序列化操作。

  在对实现了Externalizable接口的类的对象进行反序列化时,会先调用类的不带参数的构造方法,这是有别于默认反序列方式的。如果把类的不带参数的构造方法删除,或者把该构造方法的访问权限设置为private、默认或protected级别,会抛出java.io.InvalidException: no valid constructor异常。

  四. 可序列化类的不同版本的序列化兼容性

  凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:

private static final long serialVersionUID;


  以上serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。

  类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高哦啊serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地定义serialVersionUID有两种用途:

  1) 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

  2) 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

分享到:
评论

相关推荐

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制...

    Java工程师面试复习指南

    序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器...

    人工智能-项目实践-搜索引擎-java实验1-实现搜索引擎的倒排索引数据结构

    第三是熟悉对象的序列化和反序列化 作为类的方法来实现下面二个方法 ◦public abstract void writeObject(ObjectOutputStream out); ◦public abstract void readObject(ObjectInputStream in); 要熟悉对文件,...

    Java SE实践教程 源代码 下载

    9.1.4 对象XML序列化 227 9.2 练习 228 9.2.1 我的联系手册(JPA实现) 228 9.2.2 我的联系手册(JAXB实现) 238 9.3 小结 242 第10章 准备环球旅行——应用程序国际化 243 10.1 讲解 244 10.1.1 概念介绍 ...

    Java SE实践教程 pdf格式电子书 下载(四) 更新

    9.1.4 对象XML序列化 227 9.2 练习 228 9.2.1 我的联系手册(JPA实现) 228 9.2.2 我的联系手册(JAXB实现) 238 9.3 小结 242 第10章 准备环球旅行——应用程序国际化 243 10.1 讲解 244 10.1.1 概念介绍 ...

    廖雪峰 Java 教程.doc

    序列化 Reader Writer PrintStream和PrintWriter 日期与时间 基本概念 Date和Calendar LocalDateTime ZonedDateTime DateTimeFormatter Instant 最佳实践 单元测试 编写JUnit测试 使用Fixture 异常...

    Java SE实践教程 pdf格式电子书 下载(一) 更新

    9.1.4 对象XML序列化 227 9.2 练习 228 9.2.1 我的联系手册(JPA实现) 228 9.2.2 我的联系手册(JAXB实现) 238 9.3 小结 242 第10章 准备环球旅行——应用程序国际化 243 10.1 讲解 244 10.1.1 概念介绍 ...

    Java课堂笔记、代码、java核心知识点梳理、java笔试面试资料.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java interview-高级Java面试题2023.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    『Java八股文』Java面试套路,Java进阶学习,打破内卷拿大厂Offer,升职加薪!.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java面试总结.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java面试宝典.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java面试笔记.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java面试知识总结.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java面试资源概览2023最新

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

    Java 面试题汇总.zip

    Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等...

Global site tag (gtag.js) - Google Analytics