Java对象序列化
Java 1.1增添了一种有趣的特性,名为“对象序列化”(Object Serialization)。它面向那些实现了Serializable接口的对象,可将它们转换成一系列字节,并可在以后完全恢复回原来的样子。这一过程亦可通过网络进行。这意味着序列化机制能自动补偿操作系统间的差异。换句话说,可以先在Windows机器上创建一个对象,对其序列化,然后通过网络发给一台Unix机器,然后在那里准确无误地重新“装配”。不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。
就其本身来说,对象的序列化是非常有趣的,因为利用它可以实现“有限持久化”。请记住“持久化”意味着对象的“生存时间”并不取决于程序是否正在执行——它存在或“生存”于程序的每一次调用之间。通过序列化一个对象,将其写入磁盘,以后在程序重新调用时重新恢复那个对象,就能圆满实现一种“持久”效果。之所以称其为“有限”,是因为不能用某种“persistent”(持久)关键字简单地地定义一个对象,并让系统自动照看其他所有细节问题(尽管将来可能成为现实)。相反,必须在自己的程序中明确地序列化和组装对象。
语言里增加了对象序列化的概念后,可提供对两种主要特性的支持。Java 1.1的“远程方法调用”(RMI)使本来存在于其他机器的对象可以表现出好象就在本地机器上的行为。将消息发给远程对象时,需要通过对象序列化来传输参数和返回值。对象的序列化也是Java Beans必需的,后者由Java 1.1引入。使用一个Bean时,它的状态信息通常在设计期间配置好。程序启动以后,这种状态信息必须保存下来,以便程序启动以后恢复;具体工作由对象序列化完成。
对象的序列化处理非常简单,只需对象实现了Serializable接口即可(该接口仅是一个标记,没有方法)。在Java 1.1中,许多标准库类都发生了改变,以便能够序列化——其中包括用于基本数据类型的全部封装器、所有集合类以及其他许多东西。甚至Class对象也可以序列化(第11章讲述了具体实现过程)。
为序列化一个对象,首先要创建某些OutputStream对象,然后将其封装到ObjectOutputStream对象内。此时,只需调用writeObject()即可完成对象的序列化,并将其发送给OutputStream。相反的过程是将一个InputStream封装到ObjectInputStream内,然后调用readObject()。和往常一样,我们最后获得的是指向一个上溯造型Object的句柄,所以必须下溯造型,以便能够直接设置。
对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图”,而且能追踪对象内包含的所有句柄并保存那些对象;接着又能对每个对象内包含的句柄进行追踪;以此类推。我们有时将这种情况称为“对象网”,单个对象可与之建立连接。而且它还包含了对象的句柄数组以及成员对象。若必须自行操纵一套对象序列化机制,那么在代码里追踪所有这些链接时可能会显得非常麻烦。在另一方面,由于Java对象的序列化似乎找不出什么缺点,所以请尽量不要自己动手,让它用优化的算法自动维护整个对象网。下面这个例子对序列化机制进行了测试。它建立了许多链接对象的一个“Worm”(蠕虫),每个对象都与Worm中的下一段链接,同时又与属于不同类(Data)的对象句柄数组链接:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; class Data implements Serializable
{
private int i; Data(int x)
{
i = x;
} public String toString()
{
return Integer.toString(i);
}
} public class Worm implements Serializable
{
// Generate a random int value:
private static int r()
{
return (int) (Math.random() * 10);
} private Data[] d = { new Data(r()), new Data(r()), new Data(r()) };
private Worm next;
private char c; // Value of i == number of segments
Worm(int i, char x)
{
System.out.println(" Worm constructor: " + i);
c = x;
if (--i > 0)
next = new Worm(i, (char) (x + 1));
} Worm()
{
System.out.println("Default constructor");
} public String toString()
{
String s = ":" + c + "(";
for (int i = 0; i < d.length; i++)
s += d[i].toString();
s += ")";
if (next != null)
s += next.toString();
return s;
} public static void main(String[] args)
{
Worm w = new Worm(6, 'a');
System.out.println("w = " + w);
try
{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
out.writeObject("Worm storage");
out.writeObject(w);
out.close(); // Also flushes output
ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
String s = (String) in.readObject();
Worm w2 = (Worm) in.readObject();
System.out.println(s + ", w2 = " + w2);
} catch (Exception e)
{
e.printStackTrace();
}
try
{
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject("Worm storage");
out.writeObject(w);
out.flush();
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
String s = (String) in.readObject();
Worm w3 = (Worm) in.readObject();
System.out.println(s + ", w3 = " + w3);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
更有趣的是,Worm内的Data对象数组是用随机数字初始化的(这样便不用怀疑编译器保留了某种原始信息)。每个Worm段都用一个Char标记。这个Char是在重复生成链接的Worm列表时自动产生的。创建一个Worm时,需告诉构建器希望它有多长。为产生下一个句柄(next),它总是用减去1的长度来调用Worm构建器。最后一个next句柄则保持为null(空),表示已抵达Worm的尾部。
上面的所有操作都是为了加深事情的复杂程度,加大对象序列化的难度。然而,真正的序列化过程却是非常简单的。一旦从另外某个流里创建了ObjectOutputStream,writeObject()就会序列化对象。注意也可以为一个String调用writeObject()。亦可使用与DataOutputStream相同的方法写入所有基本数据类型(它们有相同的接口)。
有两个单独的try块看起来是类似的。第一个读写的是文件,而另一个读写的是一个ByteArray(字节数组)。可利用对任何DataInputStream或者DataOutputStream的序列化来读写特定的对象;正如在关于连网的那一章会讲到的那样,这些对象甚至包括网络。一次循环后的输出结果如下:
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w = :a(262):b(100):c(396):d(480):e(316):f(398)
Worm storage, w2 = :a(262):b(100):c(396):d(480):e(316):f(398)
Worm storage, w3 = :a(262):b(100):c(396):d(480):e(316):f(398)
可以看出,装配回原状的对象确实包含了原来那个对象里包含的所有链接。
注意在对一个Serializable(可序列化)对象进行重新装配的过程中,不会调用任何构建器(甚至默认构建器)。整个对象都是通过从InputStream中取得数据恢复的。
作为Java 1.1特性的一种,我们注意到对象的序列化并不属于新的Reader和Writer层次结构的一部分,而是沿用老式的InputStream和OutputStream结构。所以在一些特殊的场合下,不得不混合使用两种类型的层次结构。
Java对象序列化的更多相关文章
- Java对象序列化剖析
对象序列化的目的 1)希望将Java对象持久化在文件中 2)将Java对象用于网络传输 实现方式 如果希望一个类的对象可以被序列化/反序列化,那该类必须实现java.io.Serializable接口 ...
- 理解Java对象序列化
http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html 1. 什么是Java对象序列化 Java平台允许我们在内存中创 ...
- java 对象序列化与反序列化
Java序列化与反序列化是什么? 为什么需要序列化与反序列化? 如何实现Java序列化与反序列化? 本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为 ...
- java 对象序列化
java 对象序列化 package org.rui.io.serializable; import java.io.ByteArrayInputStream; import java.io.Byte ...
- 理解Java对象序列化(二)
关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制.在撰写本文时,既参考了Th ...
- 关于 Java 对象序列化您不知道的 5 件事
数年前,当和一个软件团队一起用 Java 语言编写一个应用程序时,我体会到比一般程序员多知道一点关于 Java 对象序列化的知识所带来的好处. 关于本系列 您觉得自己懂 Java 编程?事实上,大多数 ...
- java 对象序列化 RMI
对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中.JVM停止之后,这些状态就丢失了.在很多情况下,对象的内部状态是需要被持久化下来的.提到持久化,最直接的做法是保存到文件系统或是数 ...
- Java对象序列化入门
Java对象序列化入门 关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制 ...
- Java对象序列化与反序列化一 JSON
Java对象序列化与反序列化一 JSON 1. 依赖库 jackson-all-1.6.1.jar 2. 代码 public class Student { private String nam ...
- Java对象序列化/反序列化的注意事项(转)
Java对象序列化 对于一个存在Java虚拟机中的对象来说,其内部的状态只是保存在内存中.JVM退出之后,内存资源也就被释放,Java对象的内部状态也就丢失了.而在很多情况下,对象内部状态是需要被持久 ...
随机推荐
- 支付宝ios支付请求Java服务端签名报的一个错(ALI40247) 原创
今天做app的支付宝支付,遇到些问题,以前做支付宝支付签名都是直接在客户端App进行,今天下了最新版本ios的支付宝支付demo,运行demo时底部有红色的显眼字体,告知用户签名必须在服务端进行... ...
- [html5] 学习笔记-服务器推送事件
1.HTML5服务器推送事件介绍 服务器推送事件(Server-sent Events)是Html5规范的一个组成部分,可以用来从服务端实时推送数据到浏览器端. 传统的服务器推送技术----WebSo ...
- u3d脚本生命周期
- 自己动手系列——实现一个简单的ArrayList
ArrayList是Java集合框架中一个经典的实现类.他比起常用的数组而言,明显的优点在于,可以随意的添加和删除元素而不需考虑数组的大小.处于练手的目的,实现一个简单的ArrayList,并且把实现 ...
- jQuery --checkbox全选和取消全选简洁高效的解决办法
最近在公司做了一个小项目,其中有一个全选和取消全选的这么一个模块,搞了半天找不到一种最佳的解决方案!后来通过各种努力找到了一种简洁高效的解决办法,这里想和大家分享一下.有问题的话,还望各路大神指导一二 ...
- uml系列(七)——交互图
交互图是uml中描述系统中的对象如何进行交互动作的 . 废话不多说,还是来张图: 概念 交互图,主要描述的是系统中的一组对象的消息的传递的,为对象间的交互定义了一个可视的表示方法. ...
- runtime ---- iOS
1.runtime是什么?runtime是一套底层的C语言的API(包括C语言数据类型,C语言函数) 实际上平时我们写的OC代码底层都是基于runtime,实际上也就是最后都转成了runtime代码 ...
- matlab图像显示程序模板
在这个程序中:优秀的模板值得学习,变量的定义字典值得学习 .^ .* ./的使用: 图形的显示及标注 % 脚本文件: 功率计算 % 文件名:cac_power.m % 目标:随着电阻值的 ...
- Hadoop1.0.3环境搭建流程
0x00 大数据平台相关链接 官网:http://hadoop.apache.org/ 主要参考教程:http://www.cnblogs.com/xia520pi/archive/2012/05/1 ...
- jquery实现横向导航
<!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...