在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. mysql 系统性浅聊 myisam 存储引擎【原创】

    >>思维导图 >>介绍 mysql中的存储引擎都是以插件的形式存在,目前用的最多存储引擎就是innodb和myisam.MySQL5.5.5以后(包括5.5.5)默认使用Inn ...

  2. nignx 测试配置文件

    nginx -t nginx: the configuration file /usr/local/nginx-1.2.9/conf/nginx.conf syntax is ok nginx: co ...

  3. 配置scrapy-splash+python爬取医院信息(利用了scrapy-splash)

    北京艾丽斯妇科医院(http://fuke.fuke120.com/) 首先先说一下配置splash 1.利用pip安装scrapy-splash库 pip install scrapy-splash ...

  4. 分享Sql Server 2008 r2 数据备份,同步服务器数据(一.本地备份)

    最近在部署一个系统,处于数据安全的考虑,因此对相应的数据库服务器定时备份,以及数据同步到备份服务上.之前在另外的一个项目中也做过相应的操作,但是操作都是按照查找到的文章一步一步的操作,碰到一些细节问题 ...

  5. Sublime Text 3 常用快捷键

    一. 选择类       Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本.     Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并 ...

  6. JavaWeb学习总结(二)——Tomcat服务器学习和使用(一)(转)

    转载自 http://www.cnblogs.com/xdp-gacl/p/3734395.html 一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的serve ...

  7. UAC

    UAC and Security Shield Icon UAC in Wiki User Account Control (UAC) is a technology and security inf ...

  8. JAVA设计模式之:命令模式

    *通常情况下:行为请求者与实现者通常呈现一种高度耦合状态.有时要对行为进行变更处理处理.高度耦合方式就显得不合适. * 将行为请求者与行为实现者解耦,将一组行为抽象为对象.实现二者之间的松耦合. 这就 ...

  9. 关于一些常用的linux命令

    作为一个程序员了解linux系统还是很必要的,下面我为大家提供一些linux系统中比较常的命令 一.linux系统命令 1.Cd  进入指定目录 2.ls 显示当前目录下的文件 3.ls-a 显示所有 ...

  10. Ubuntu 下使用 ZTE ME3630 4G 模块

    之前在 AM5728 开发板上使用过这个模块,用来在野外采集数据上传到服务器.最近接触另外一个项目,做一个演示用的样机,需要移动的,也是采用了这个模块来上传数据.样机环境是 Ubuntu 16.04 ...