Java基础系列8:Java的序列化与反序列化

一 简介

把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复为对象的过程称为对象的反序列化
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

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

二 Java中的序列化API

java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中;java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回

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

对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。

对象反序列化的步骤如下:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。

三 使用Serializable接口实现的实例

首先定义了一个实现了Serializable接口WebSite的实体类

package cn.zifangsky.serializable;

import java.io.Serializable;

public class WebSite implements Serializable {
	private static final long serialVersionUID = 1835573222135484360L;

	private String siteName;
	private String siteUrl;
	private String webMaster;

	public WebSite() {

	}

	public WebSite(String siteName, String siteUrl, String webMaster) {
		this.siteName = siteName;
		this.siteUrl = siteUrl;
		this.webMaster = webMaster;
	}

	public String getSiteName() {
		return siteName;
	}

	public void setSiteName(String siteName) {
		this.siteName = siteName;
	}

	public String getSiteUrl() {
		return siteUrl;
	}

	public void setSiteUrl(String siteUrl) {
		this.siteUrl = siteUrl;
	}

	public String getWebMaster() {
		return webMaster;
	}

	public void setWebMaster(String webMaster) {
		this.webMaster = webMaster;
	}

	public String toString() {
		return "WebSite [siteName=" + siteName + ", siteUrl=" + siteUrl + ", webMaster=" + webMaster + "]";
	}

}

然后进行序列化和反序列化测试:

package cn.zifangsky.serializable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestSerialize {

	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		TestSerialize.serializeWebSite();
		TestSerialize.deserializeWebSite();
	}

	/**
	 * 使用ObjectOutputStream 序列化WebSite
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 * 
	 * */
	public static void serializeWebSite() throws FileNotFoundException, IOException{
		WebSite webSite = new WebSite();
		webSite.setSiteName("zifangsky的个人博客");
		webSite.setSiteUrl("http://www.zifangsky.cn");
		webSite.setWebMaster("zifangsky");

		//序列化
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("C:/Users/Administrator/Desktop/test.txt")));
		objectOutputStream.writeObject(webSite);
		objectOutputStream.flush();
		objectOutputStream.close();
	}

	/**
	 * 使用ObjectInputStream 反序列化WebSite
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 * @throws ClassNotFoundException 
	 * 
	 * */
	public static void deserializeWebSite() throws FileNotFoundException, IOException, ClassNotFoundException{
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("C:/Users/Administrator/Desktop/test.txt")));
		//反序列化
		WebSite webSite = (WebSite) objectInputStream.readObject();
		objectInputStream.close();

		System.out.println(webSite);
	}

}

输出:

WebSite [siteName=zifangsky的个人博客, siteUrl=http://www.zifangsky.cn, webMaster=zifangsky]

四 使用Externalizable接口实现的实例

实现了Externalizable接口的实体类:

package cn.zifangsky.serializable;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class ExternalizableDemo implements Externalizable{
	private String name;
	static {
		System.out.println("调用静态代码块");
	}

	public ExternalizableDemo() {
		System.out.println("调用无参构造方法");
	}

	public ExternalizableDemo(String name) {
		this.name = name;
		System.out.println("调用有参构造方法");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String toString() {
		return "ExternalizableDemo [name=" + name + "]";
	}

	/**
	 * ObjectOutputStream会调用writeExternal(ObjectOutput out))这个方法进行序列化
	 * */
	public void writeExternal(ObjectOutput out) throws IOException {
		out.writeObject(name);
	}

	/**
	 * ObjectInputStream会调用readExternal(ObjectInput in)这个方法进行反序列化
	 * */
	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		name = (String) in.readObject();
	}

}

然后进行序列化和反序列化测试:

package cn.zifangsky.serializable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestExternalizable {

	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		ExternalizableDemo demo = new ExternalizableDemo("hello");
		// 序列化
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(
				new FileOutputStream(new File("C:/Users/Administrator/Desktop/test2.txt")));
		objectOutputStream.writeObject(demo);
		objectOutputStream.flush();
		objectOutputStream.close();

		//反序列化
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("C:/Users/Administrator/Desktop/test2.txt")));
		ExternalizableDemo demo2 = (ExternalizableDemo) objectInputStream.readObject();
		objectInputStream.close();
		System.out.println(demo2);
	}

}

输出:

调用静态代码块
调用有参构造方法
调用无参构造方法
ExternalizableDemo [name=hello]

注:

(1)使用Externalizable进行序列化时,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中

(2)Externalizable接口继承自Serializable接口。两者的区别如下:

假设有一个Customer类的对象需要序列化,如果这个类仅仅实现了这个接口,那么序列化和反序列化的方式如下:ObjectOutputStream采用默认的序列化方式,对于这个类的非static,非transient的实例变量进行序列化,ObjectInputStream采用默认的反序列化方式,对于这个类的非static,非transient的实例变量进行反序列化。

如果这个类不仅实现了Serializable接口,而且定义了readObject(ObjectInputStream in)和 writeObject(ObjectOutputStream out)方法,那么将按照如下的方式进行序列化和反序列化:

ObjectOutputStream会调用这个类的writeObject方法进行序列化,

ObjectInputStream会调用相应的readObject方法进行反序列化。

实现Externalizable接口的类完全由自身来控制序列化的行为。而且必须实现writeExternal(ObjectOutput out)和readExternal(ObjectInput in)。那么将按照如下的方式进行序列化和反序列化:

ObjectOutputStream会调用这个类的writeExternal方法进行序列化,

ObjectInputStream会调用相应的readExternal方法进行反序列化。

PS:

如果想要进一步了解,可以参考这篇文章:http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html

参考文章:

(1)http://www.cnblogs.com/xdp-gacl/p/3777987.html

(2)http://www.cnblogs.com/rollenholt/archive/2012/11/26/2789445.html

时间: 2024-10-08 19:56:05

Java基础系列8:Java的序列化与反序列化的相关文章

【BigData】Java基础_ObjectOutputStream与ObjectInputStream实现序列化与反序列化

1.概念 ObjectOutputStream用于序列化 ObjectOutputStream用于反序列化 所谓的序列化,其实就是将对象转化为二进制 举个例子说明: 例如,我在京东上买了一张木床,京东发货的时候,肯定不会给我发一张已经拼接好的木床,因为这样不方便运输,那么快递公司会将床先拆开,然后附上安装说明书,这就叫做序列化,等我拿到床的时候,我再把床按照说明书组装起来,这就叫做反序列化. 2.代码案例 2.1 简单对象的序列化与反序列化 文件1:User.java 一个存储用户信息的java

Java基础学习总结——Java对象的序列化和反序列化

一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中: 2) 在网络上传送对象的字节序列. 在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存.比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些s

【小白的java成长系列】——Java基础知识

今天来说说java的基础知识,个人感觉都不知道要说啥的,还是为后面的内容做一些铺垫吧~ 今天主要说的都是java面向对象之前的基础知识,比如数据类型呀,表达式运算符呀~等等一系列的知识,下节来说说面向对象.今天这节我就不用程序来说明,直接用文字说明.因为个人感觉真木有啥好说的,这些程序后续都会说到的,比较简单,写写就会了的..好吧~开始了... 1. Java数据类型划分: 基本数据类型:都是一个个具体的值 数值型:表示具体的数字,所有的整数默认情况下都是int,所有的小数都是double型的

《Java 基础系列》初步整理

<Java 基础系列>初步整理大概有 12 篇,主要内容为.: 抽象类和接口内部类修饰符装箱拆箱注解反射泛型异常集合IO字符串其他第一篇我们来聊聊抽象类和接口. "抽象类和接口"听起来是非常普遍的东西,有些朋友会觉得:这个太基础了吧,有啥好说的,你又来糊弄我. 这里写图片描述 事实上我在面试中不仅一次被问到相关的问题: 抽象类和接口之间的区别?什么时候创建抽象类?什么时候创建接口?设计框架时该如何选择?我比较喜欢这样的问题,答案可深可浅,体现了我们对日常工作的思考. 我们什

夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理

目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 使用final修饰方法会提高速度和效率吗 使用final修饰变量会让变量的值不能被改变吗: 如何保证数组内部不被修改 final方法的三条规则 final 和 jvm的关系 写 final 域的重排序规则 读 final 域的重排序规则 如果 final 域是引用类型 参考文章 微信公众号 Jav

夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接口与抽象类的本质区别是什么? 基本语法区别 设计思想区别 如何回答面试题:接口和抽象类的区别? 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl

夯实Java基础系列7:一文读懂Java 代码块和执行顺序

目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块简介 Java代码块使用 局部代码块 构造代码块 静态代码块 Java代码块.构造方法(包含继承关系)的执行顺序 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github

夯实Java基础系列9:深入理解Class类和Object类

目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); registerNatives()方法; Clone()方法实现浅拷贝 getClass()方法 equals()方法 hashCode()方法; toString()方法 wait() notify() notifAll() finalize()方法 CLass类和Object类的关系 参考文章 微信公众号 Ja

夯实Java基础系列10:深入理解Java中的异常体系

目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调用链 自定义异常 异常的注意事项 当finally遇上return JAVA异常常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 - Java异常 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c

夯实Java基础系列13:深入理解Java中的泛型

目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下Star.Fork.Watch三连哈,感谢你的