序列化的概念及使用场合

序列化就是把对象转化为字节序列并持久化保存,可以保存在内存中、磁盘文件系统,甚至通过网络传递,并能够在以后将这个字节序列完全恢复为原来的对象。

对象序列化的概念引入Java是为了支持两种主要特性:

  • 一是为了远程调用(Remote Method Invocation,RMI),它使存活于其他计算机上的对象使用起来就像是存活于本机上一样。当想远程对象发送消息时,需要通过对象序列化来传输参数和返回值。
  • 二是对于Java Beans来说,对象的序列化也是必须的。使用一个Bean时,一般情况下是在设计阶段对它的状态信息进行配置,而这种状态信息必须保存下来,并在程序启动时进行后期恢复。

序列化操作步骤:

  1. 要使得一个对象可以被序列化,首先要实现实现接口Serializable(该接口仅是一个标记接口,不包括任何方法);
  2. 使用ObjectOutputStream包装一个OutputStream对象,在调用ObjectOutputStream的writeObject()来序列化;
  3. 使用ObjectInputStream包装一个InputStream对象,在调用ObjectInputStream的readObject()来反序列化;

因为序列化最终是字节序列,所以必须字节流,而不能使用字符流(关于字节流和字符流请参考这里)。

对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图”,而且能追踪对象内包含的所有引用并保存那些对象;接着又能对每个这样的对象内包含的引用进行追踪;以此类推。这种情况有时被称为“对象网”,单个对象可与之建立连接,而且它还包含了对象的引用数组以和成员对象。如果必须保持一套自己的对象序列化机制,那么维护那些可追踪到所有链接的代码可能会显得非常麻烦。然而,由于 Java的对象序列化似乎找不出什么缺点,所以请尽量不要自己动手,让它用优化的算法自动维护整个对象网。

序列化Demo

public class App
{
public static void main( String[] args ) throws Exception, IOException
{
User user=new User();
user.setName("net.oseye");
user.setAge(18);; //序列化
//使用ObjectOutputStream包装OutputStream
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("out.txt"));
out.writeObject("下面是序列化的User:");
out.writeObject(user);
out.close(); //反序列化
//
ObjectInputStream in=new ObjectInputStream(new FileInputStream("out.txt"));
System.out.println(in.readObject());
//查看反序列化后的对象类型,方便反射
Object obj=in.readObject();
System.out.println(obj.getClass()); user=(User)obj;
System.out.println(user);
System.out.println("user的name:"+user.getName());
System.out.println("user的age:"+user.getAge());
in.close();
}
} //实现标记接口Serializable
@SuppressWarnings("serial")
class User implements Serializable{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
} private int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}

输出

下面是序列化的User:
class net.oseye.SerializationDemo.User
net.oseye.SerializationDemo.User@9980d5
user的name:net.oseye
user的age:18

如果我们不想序列化某个字段可以使用transient(瞬时)关键字来修饰字段,如:

public class App
{
public static void main( String[] args ) throws Exception, IOException
{
//如前面示例代码....
}
} //实现标记接口Serializable
class User implements Serializable{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
} private transient int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}

这样就不会序列化age字段了。

使用Externalizable定制序列化

使用transient关键字可以简单定制序列化,但如果更复杂的定制可以使用Externalizable接口代替标记接口Serializable,因为Externalizable有序列化和反序列化的方法

public class App
{
public static void main( String[] args ) throws Exception, IOException
{
//如前面示例代码....
}
} //实现标记接口Externalizable
class User implements Externalizable{
public User(){}
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
} private transient int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
} public void writeExternal(ObjectOutput out) throws IOException {
this.name="已经被序列化了:"+this.name;
out.writeObject(this.name);
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
this.name=(String)in.readObject();
}
}

输出

下面是序列化的User:
class net.oseye.SerializationDemo.User
net.oseye.SerializationDemo.User@ff2413
user的name:已经被序列化了:net.oseye
user的age:0

问题:我发现使用Externalizable接口实现的类必须显示声明构造函数,如上例不显示声明

public User(){}

将会报异常:

Exception in thread "main" java.io.InvalidClassException: net.oseye.SerializationDemo.User; no valid constructor

至于原因有待查明....,如果你知道也请告诉我,谢谢。

使用Serializable定制序列化

其实如果你不是特别坚持使用Externalizable接口的话,使用Serializable接口也可以实现定制,但却使用迷惑,因为需要添加

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException;

这两个方法,如果你细心你会发现和Externalizable接口的中的两个方法很像。迷惑的地方是Serializable是标记接口,而我们感觉无端增加了两个私有方法!!

一旦在接口Serializable的实现类中添加了上面两个方法,序列化和反序列化就会自动调用:

//实现标记接口Serializable
@SuppressWarnings("serial")
class User implements Serializable{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
} private int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
} private void writeObject(ObjectOutputStream out) throws IOException {
this.name="已经被序列化了:"+this.name;
out.writeObject(this.name);
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
this.name=(String)in.readObject();
}
}

Java对象序列化的使用和定制的更多相关文章

  1. 理解Java对象序列化(二)

    关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制.在撰写本文时,既参考了Th ...

  2. java 对象序列化 RMI

    对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中.JVM停止之后,这些状态就丢失了.在很多情况下,对象的内部状态是需要被持久化下来的.提到持久化,最直接的做法是保存到文件系统或是数 ...

  3. Java对象序列化入门

      Java对象序列化入门 关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制 ...

  4. 深入理解Java对象序列化

    关于Java序列化的文章早已是汗牛充栋了,本文是对我个人过往学习,理解及应用Java序列化的一个总结.此文内容涉及Java序列化的基本原理,以及多种方法对序列化形式进行定制.在撰写本文时,既参考了Th ...

  5. Java对象序列化与RMI

    对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中.JVM停止之后,这些状态就丢失了.在很多情况下,对象的内部状态是需要被持久化下来的.提到持久化,最直接的做法是保存到文件系统或是数 ...

  6. 理解Java对象序列化【转】

      原文链接:http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html 关于Java序列化的文章早已是汗牛充栋了,本文是 ...

  7. Java对象序列化剖析

    对象序列化的目的 1)希望将Java对象持久化在文件中 2)将Java对象用于网络传输 实现方式 如果希望一个类的对象可以被序列化/反序列化,那该类必须实现java.io.Serializable接口 ...

  8. 理解Java对象序列化

    http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html 1. 什么是Java对象序列化 Java平台允许我们在内存中创 ...

  9. java 对象序列化与反序列化

    Java序列化与反序列化是什么? 为什么需要序列化与反序列化? 如何实现Java序列化与反序列化? 本文围绕这些问题进行了探讨. 1.Java序列化与反序列化  Java序列化是指把Java对象转换为 ...

随机推荐

  1. Angular - - angular.equals

    angular.equals 对比两个对象/值是否相等.支持值类型.正则表达式.数组和对象. 如果下列至少有一个是正确的,则将两个对象/值视为相等. 两个对象/值能通过===比较. 两个对象/值是同一 ...

  2. NodeJS异步I/O解析

    在现在的项目开发中,任何一个大型项目绝对不是简简单单的采用一个种语言和一种框架,因为每种语言和框架各有优势,与其死守一个,不与取各家之所长,依次得到一个高性能.搞扩展的产品. 对于一个.NET开发者, ...

  3. ASP.NET Zero--15.一个例子(8)商品分类管理-权限控制

    1.添加权限常量 打开文件AppPermissions.cs [..\MyCompanyName.AbpZeroTemplate.Core\Authorization\AppPermissions.c ...

  4. Fiddler 模拟请求的操作方法

    此文记录使用Fidder Web Debugger工具,模拟请求的操作步骤! 首先简述一下fiddler的使用: 1.下载安装Fidder抓包工具. 2.打开fiddler发现有左边的栏有请求的url ...

  5. 微信小程序之快速接入七牛云

    小程序为什么要接入云? 目前,开发者在开发小程序过程中,主要遇到以下几个问题: 小程序发布大小超限 微信官方限制小程序的发布代码不能超过 1MB,而在实际开发过程中,一般的小程序难免会有图片等富媒体文 ...

  6. Spark工作机制简述

    Spark工作机制 主要模块 调度与任务分配 I/O模块 通信控制模块 容错模块 Shuffle模块 调度层次 应用 作业 Stage Task 调度算法 FIFO FAIR(公平调度) Spark应 ...

  7. Objective-c runtime方法替换引发的死循环

    在OC中: API: class_addMethod往一个Class里添加method API: class_getInstanceMethod或class_getClassMethod可以判断某个S ...

  8. iOS视频压缩处理

    最近忙于项目开发, 昨天才完成整个项目的开发, 今天就抽出时间, 分享一下我在开发中所涉及到的技术问题! 由于近期开发涉及到视频, 所以视频压缩, 上传, 播放等一系列功能都是要涉及到的, 所以在此, ...

  9. Android仿微信朋友圈,全文收起功能,附源码

    在众多的社交类软件中,朋友圈是必不可少的,可以与好友.同学等分享自己的日常和有意思的事情,在开发社交类App时,朋友圈发表的内容你不可能让他全部显示,全部显示的话用户体验度会非常不好,这时就要用到全文 ...

  10. 用phpcms如何将静态页面制作成企业网站,头部加尾部

    首先,先要准备好这个静态网页的源文件,如图 bs里面是一些css和js的文件,img则是放图片的,文件中的index是网页的首页 运行一下,看看 是这样的 然后打开phpcms文件,上篇博客中有提到, ...