在java中,对一个对象进行序列化操作,其有如下两种方式:

第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializable接口的类,其序列化过程是默认的,当然,也可以通过在该类中重写如下四个方法对序列化的过程进行控制:

0. private Object writeReplace() throws ObjectStreamException;
1. private void writeObject(java.io.ObjectOutputStream out) throws IOException;
2. private void readObject(java.io.ObjectInputStream in) throws Exception;
3. private Object readResolve() throws ObjectStreamException;

其中,方法0方法1是序列化的过程中会进行调用的方法,方法2方法3是反序列化过程中会进行调用的方法。其执行的顺序是按照以上方法的排列顺序从上到下执行的。

在进行序列化时候,其序列化类java.io.ObjectOutputStream会通过反射调用writeReplace()方法。此时,可以通过返回一个与本类兼容的对象(指的是该类的子类或者本类对象)的方式替换掉需要进行序列化的本类的对象(也就是this),使其序列化所返回的对象,需要注意的是,其返回的对象的类型是需要和所序列化的本类的类型兼容的,否则,其会报ClassCastException异常。在调用完writeReplace()方法之后,其会接着调用writeObject(ObjectOutputStream out)方法进行进一步的序列化操作。在该方法中,可以序列化额外的对象,也可以调用out.defaultWriteObject()进行默认的序列化操作,其中方法的参数out对象是其原先所创建的ObjectOutputStream对象。

对于反序列化的过程,其会先通过反序列化类ObjectInputStream对象去调用readObject(ObjectInputStream in)方法,在调用该方法的时候,其可以通过in对象进行额外的反序列化操作,也可以通过调用in.defaultReadObject()方法进行默认的反序列化操作,其中方法的参数in对象是原先所创建的ObjectInputStream对象。在调用完该方法之后,其会接着调用readResolve()方法,其方法的返回值为一个Object对象,该方法返回的对象将会代替反序列化的结果,直接将其作为反序列化的结果返回给上层调用ObjectInputStream对象readObject方法的结果。

演示代码如下:

@代码改自:http://www.cnblogs.com/yoohot/p/6019767.html

package other.serial;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* 该类用于演示说明可序列化类中重写(override)
* writeReplace()方法、writeObject(ObjectOutputStream out)方法、readObject(ObjectInputStream in)方法、readResolve()方法
* 时,其进行序列化和可序列化的调用相关过程
* @author 学徒
*
*/
public class PersonSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private PersonSingleton(String name) {
this.name = name;
}
private static PersonSingleton person = null; public static synchronized PersonSingleton getInstance() {
if (person == null)
return person = new PersonSingleton("cgl");
return person;
} private Object writeReplace() throws ObjectStreamException {
System.out.println("1 write replace start");
return this;//可修改为其他对象
} private void writeObject(java.io.ObjectOutputStream out) throws IOException {
System.out.println("2 write object start");
out.defaultWriteObject();
//out.writeInt(1);
} private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
System.out.println("3 read object start");
in.defaultReadObject();
//int i=in.readInt();
} private Object readResolve() throws ObjectStreamException {
System.out.println("4 read resolve start");
return PersonSingleton.getInstance();//不管序列化的操作是什么,返回的都是本地的单例对象
} public static void main(String[] args) throws Exception { FileOutputStream out = new FileOutputStream(new File("H://person.dat"));
ObjectOutputStream op = new ObjectOutputStream(out);
op.writeObject(PersonSingleton.getInstance());
op.close(); FileInputStream in = new FileInputStream(new File("H://person.dat"));
ObjectInputStream oi = new ObjectInputStream(in);
Object person = oi.readObject();
in = new FileInputStream(new File("H://person.dat"));
oi = new ObjectInputStream(in);
PersonSingleton person1 = (PersonSingleton) oi.readObject(); System.out.println("sington person hashcode:" + person.hashCode());
System.out.println("sington person1 hashcode:" + person1.hashCode());
System.out.println("singleton getInstance hashcode:" + PersonSingleton.getInstance().hashCode());
System.out.println("singleton person equals:" + (person == PersonSingleton.getInstance()));
System.out.println("person equals1:" + (person1 == person));
}
} 输出结果:
1 write replace start
2 write object start
3 read object start
4 read resolve start
3 read object start
4 read resolve start
sington person hashcode:13620718
sington person1 hashcode:13620718
singleton getInstance hashcode:13620718
singleton person equals:true
person equals1:true

第二种:

通过实现Externalizable接口,其中Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由类自身来控制序列化的行为(通过重写writeExternal()与readExternal()方法)

@代码改自:dovecat.iteye.com/blog/66044

package other.serial;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
/**
* 用于演示通过实现Externalizable接口进行序列化和反序列化过程的案例
* @author 学徒
*
*/
public class ExternalizableTest implements Externalizable
{
public ExternalizableTest()
{
System.out.println("反序列化的过程中进行调用");
} private String message; public String getFoo()
{
return message;
} public void setMessage(String message)
{
this.message = message;
} private Object writeReplace() throws ObjectStreamException
{
System.out.println("writeReplace invoked");
return this;
} private void writeObject(ObjectOutputStream out) throws IOException
{
System.out.println("writeObject invoked");
} private void readObject(ObjectInputStream in) throws IOException
{
System.out.println("readObject invoked");
} private Object readResolve() throws ObjectStreamException
{
System.out.println("readResolve invoked");
return this;
} @Override
public void readExternal(ObjectInput arg0) throws IOException,
ClassNotFoundException
{
System.out.println("readExternal invoked");
Object obj = arg0.readObject();
} @Override
public void writeExternal(ObjectOutput arg0) throws IOException
{
System.out.println("writeExternal invoked");
arg0.writeObject("Hello world");
} public static void main(String[] args) throws IOException,
ClassNotFoundException
{
ExternalizableTest fooimpl = new ExternalizableTest();
fooimpl.serialize();
} public Object serialize() throws IOException, ClassNotFoundException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
运行结果:
反序列化的过程中进行调用
writeReplace invoked
writeExternal invoked
反序列化的过程中进行调用
readExternal invoked
readResolve invoked

在此writeExternal和readExternal的作用与writeObject和readObject一样,且当同同时存在时候,只会调用writeExternal和readExternal方法。

序列化所需要的注意事项:

  1. 反序列化(实现Serializable接口的序列化对象)无需通过构造器初始化对象,实现Externalizable进行序列化时,需要提供一个无参的构造函数供反序列化的过程进行对象创建的调用

  2. 如果使用序列化机制向文件中写入了多个对象,那么取出和写入的顺序必须一致

  3. Java对类的对象进行序列化时,若类中存在对象引用(且值不为null),也会对类的引用对象进行序列化(前提是该引用对象的类实现了序列化相关的接口,如果该对象值不为null且没有实现序列化相关的接口且其没有被transient关键字进行修饰时,在序列化时其会抛出java.io.NotSerializableException异常)

  4. 反序列化时必须要有序列化对象的类的class文件

  5. 当某个字段被声明为transient后,默认序列化机制就会忽略该字段。

  6. 如是一个类是可序列化的,那么它的子类也是可序列化的。

  7. 当我们同时实现了两个interface的时候,JVM只运行Externalizable接口里面的writeExternal和readExternal方法对序列化内容进行处理.

@汇总内容出处:http://blog.csdn.net/gitar520/article/details/7613122

Serializable接口和Externalizable接口各自的优缺点:

Serializable接口:

优点:内建支持
优点:易于实现
缺点:占用空间过大
缺点:由于额外的开销导致速度变比较慢

Externalizable接口:

优点:开销较少(程序员决定存储什么)
优点:可能的速度提升
缺点:虚拟机不提供任何帮助,也就是说所有的工作都落到了开发人员的肩上

Serializable和Externalizable的比较汇总:

序 号 区 别 Serializable Externalizable
1 实现复杂度 实现简单,Java对其有内建支持 实现复杂,由开发人员自己完成
2 执行效率 所有对象由Java统一保存,性能较低 开发人员决定哪个对象保存,可能造成速度提升
3 保存信息 保存时占用空间大 部分存储,可以减少存储空间

关于序列化相关的更多问题,可以参看博文: http://blog.csdn.net/androiddevelop/article/details/17537841

回到目录|·(工)·)

K:java中序列化的两种方式—Serializable或Externalizable的更多相关文章

  1. Java中实现序列化的两种方式 Serializable 接口和 Externalizable接口

    对象的序列化就是将对象写入输出流中. 反序列化就是从输入流中将对象读取出来. 用来实现序列化的类都在java.io包中,我们常用的类或接口有: ObjectOutputStream:提供序列化对象并把 ...

  2. java中创建多线程两种方式以及实现接口的优点

    多线程创建方式有两种 创建线程的第一种方式.继承Thread类 1.继承Thread类 2.重写Thread类中的run方法--目的将自定义代码存储在run方法.让线程执行3.调用线程的start() ...

  3. 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口

    //继承thread类 class PrimeThread extends Thread{ long minPrime; PrimeThread(long minPrime) { this.minPr ...

  4. java实现序列化的两种方式

    1.Serializable接口 2.Externalizable接口 public class Demo2 implements Externalizable{ transient private ...

  5. 【转载】JAVA中线程的两种实现方法-实现Runnable接口和继承Thread类

    转自: http://blog.csdn.net/sunguangran/article/details/6069317 非常感谢原作者,整理的这么详细. 在java中可有两种方式实现多线程,一种是继 ...

  6. Java中创建对象的几种方式

    Java中创建对象的五种方式: 作为java开发者,我们每天创建很多对象,但是我们通常使用依赖注入的方式管理系统,比如:Spring去创建对象,然而这里有很多创建对象的方法:使用New关键字.使用Cl ...

  7. Java中创建对象的五种方式

    我们总是讨论没有对象就去new一个对象,创建对象的方式在我这里变成了根深蒂固的new方式创建,但是其实创建对象的方式还是有很多种的,不单单有new方式创建对象,还有使用反射机制创建对象,使用clone ...

  8. 【转】Java中创建对象的5种方式

    Java中创建对象的5种方式   作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象.然而这里有很多创建对象的方法,我们会在这篇文章中学到. Java中有 ...

  9. 对Java代码加密的两种方式,防止反编译

    使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...

随机推荐

  1. SQL面试题:有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列

    .请教一个面试中遇到的SQL语句的查询问题 表中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列. ------------------- ...

  2. struts2 谷歌浏览器保存date类型数据时报错

    一同事发现一个bug,在chrome上保存一个表单时,后台会报错,而在firefox上则可以正常保存. 奇怪的地方在于,后端的程序是同一个,而在浏览器上查看请求header时,两个浏览器对应的字段内容 ...

  3. Flask-admin 笔记一 (快速启用)

    1,快速启用   1) 安装flask-admin pip install flask-admin 2) 配置使用 from flask import Flask from flask_admin i ...

  4. 一个模型中有两个外键指向同一张表时,创建迁移模型时报错:“ HINT: Add or change a related_name argument to the definition for 'AnswersModel.author' or 'AnswersModel.relay_to'.”解决方案

    class AnswersModel(models.Model): author = models.ForeignKey(FrontUserModel,null=True,related_name=' ...

  5. Git 二分调试法,火速定位疑难Bug!

    你一定遇到过,一个很久没修改过的功能,莫名其妙的出现了问题?肉眼查代码.屡逻辑完全找不到问题点?前两天还好好的功能,怎么这个今天就不行了?这两天改动了这么多代码,到底是那一次改动引发的 Bug? 这样 ...

  6. 从无到有<前端异常监控系统>落地

    导火索 有一天一个测试同事的一个移动端页面白屏了,看样子是页面哪里报错了.  我自己打开页面并没有报错,最后发现报错只存在于他的手机,移动端项目又是在微信环境下,调试起来会比较麻烦,最后用他手机调试才 ...

  7. 我的Java开发学习之旅------&gt;Base64的编码思想以及Java实现

    Base64是一种用64个字符来表示随意二进制数据的方法. 用记事本打开exe.jpg.pdf这些文件时,我们都会看到一大堆乱码,由于二进制文件包括非常多无法显示和打印的字符.所以,假设要让记事本这种 ...

  8. One-Based Arithmetic

    One-Based Arithmetic time limit per test 0.5 seconds memory limit per test 256 megabytes input stand ...

  9. 【quickhybrid】H5和原生的职责划分

    前言 在JSBridge实现后,前端网页与原生的交互已经通了,接下来就要开始规划API,明确需要提供哪一些功能来供前端调用. 但是在这之前,还有一点重要工作需要做: 明确H5与Native的职责划分, ...

  10. Java中的包含义

    JAVA提供了强大的应用程序接口,既JAVA类库.他包含大量已经设计好的工具类,帮助程序员进行字符串处理.绘图.数学计算和网络应用等方面的工作.下面简单介绍JAVA核心类库中常用的组建包. 1.jav ...