当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个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; public class ObjectSaver { 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;
}
}

 输出结果如下:

  二.实现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 基础【03】序列化和反序列化的更多相关文章

  1. 【Java基础】序列化与反序列化深入分析

    一.前言 复习Java基础知识点的序列化与反序列化过程,整理了如下学习笔记. 二.为什么需要序列化与反序列化 程序运行时,只要需要,对象可以一直存在,并且我们可以随时访问对象的一些状态信息,如果程序终 ...

  2. JAVA基础之——序列化和反序列化

    1 概念 序列化,将java对象转换成字节序列的过程. 反序列化,将字节序列恢复成java对象的过程. 2 为什么要序列化? 2.1 实现数据持久化,当对象创建后,它就会一直在,但是在程序终止时,这个 ...

  3. JAVA基础之序列化与反序列化

    序列化和反序列化: 把对象转化为字节序列的过程称为序列化: 把字节序列恢复为对象的过程称为对象的反序列化: 方法: Java.io.ObjectOutputStream代表对象的输出流,writeOb ...

  4. Java基础知识➣序列化与反序列化(四)

    概述 Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据.有关对象的类型的信息和存储在对象中数据的类型. 将序列化对象写入文件之后,可以从文件 ...

  5. Java基础之序列化对象——反序列化对象(DeserializeObjects)

    控制台程序,使用如下代码能读入包含Junk对象的文件: import java.io.*; import java.nio.file.*; class DeserializeObjects { pub ...

  6. Java对象的序列化和反序列化[转]

    Java基础学习总结--Java对象的序列化和反序列化 一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化.把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用 ...

  7. 【Java】Java原生的序列化和反序列化

    写一个Java原生的序列化和反序列化的DEMO. 需序列化的类: package com.nicchagil.nativeserialize; import java.io.Serializable; ...

  8. Java对象的序列化与反序列化

    序列化与反序列化 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等.在网络传输过程中,可以是字节或是 ...

  9. Java对象的序列化与反序列化-Json篇

    说到Java对象的序列化与反序列化,我们首先想到的应该是Java的Serializable接口,这玩意在两个系统之间的DTO对象里面可能会用到,用于系统之间的数据传输.或者在RPC(远程方法调用)时可 ...

  10. java中的序列化与反序列化,还包括将多个对象序列化到一个文件中

    package Serialize; /** * Created by hu on 2015/11/7. */ //实现序列化必须实现的接口,这就是一个空接口,起到标识的作用 import java. ...

随机推荐

  1. python入门:输出1-10以内除去7的所有数(经典)

    #!/usr/bin/env python # -*-coding:utf-8 -*- #输出1-10以内除去7的所有数(经典) """ 给kaishi赋值为1,whil ...

  2. linux文件属性软硬链接知识

    链接的概念 在linux系统中,链接可分为两种:一种为硬链接,另一种为软链接或符号链接.在默认不带参数的情况下,执行ln命令创建的链接是硬链接. 如果使用ln  -s创建链接则为软链接,前面文件类型为 ...

  3. vue + axios---封装一个http请求

    在使用vue开发时,官方推荐使用axios来请求接口 // axios官方地址 https://github.com/axios/axios 但是axios并不像 vue-resource 一样拥有i ...

  4. 多线程辅助类之CyclicBarrier(四)

    CyclicBarrier是一个线程辅助类,和<多线程辅助类之CountDownLatch(三)>功能类似,都可以实现一组线程的相互等待.要说不通点,那就是CyclicBarrier在释放 ...

  5. Leetcode 814. 二叉树剪枝

    题目链接 https://leetcode-cn.com/problems/binary-tree-pruning/description/ 题目描述 给定二叉树根结点 root ,此外树的每个结点的 ...

  6. CornerStone使用教程(配置SVN,HTTP及svn简单使用)

    1.SVN配置 假设你公司svn地址为:svn://192.168.1.111/svn/ios,用户名:svnserver,密码:123456 1:填写主机地址 2:如果你的主机地址中有端口号,如为1 ...

  7. python-网络编程-01

    我们常说的计算机网络通信,值得是两台,或者多台计算机间,进行数据传输. 从计算机网络发展至今,人们使用了很多协议,但是最常用的还是tcp/ip协议,实际上这是一组协议. 当然使用python做网络编程 ...

  8. wordpress 获取站点的所有链接

    <?php include "wp-load.php"; $posts = new WP_Query('post_type=any&posts_per_page=-1 ...

  9. 《机器学习实战》笔记——AdaBoost

    笔记见备注 # _*_ coding:utf-8 _*_ from numpy import * # 简单数据集 def loadSimpData(): datMat = matrix([[1., 2 ...

  10. phpcms 后台也名称

    announce 公告 show.html 内容页 comment 评论 show_list.html 内容页评论列表 list.html 评论列表 content 内容模型 category.htm ...