K:Serializable或Externalizable对象的序列化

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

0private Object writeReplace() throws ObjectStreamException;

1private void writeObject(java.io.ObjectOutputStream out) throws IOException;

2private void readObject(java.io.ObjectInputStream in) throws Exception;

3private Object readResolve() throws ObjectStreamException;

其中方法0和方法1是序列化的过程中会进行调用的方法,方法2和方法3是反序列化过程中会进行调用的方法。其执行的顺序是按照以上方法的排列顺序从上到下执行的。在进行序列化时候,其序列化类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 的作用与writeObjectreadObject 一样,且当同同时存在时候,只会调用writeExternalreadExternal方法。

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

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接口

        优点:开销较少(程序员决定存储什么)

        优点:可能的速度提升

        缺点:虚拟机不提供任何帮助,也就是说所有的工作都落到了开发人员的肩上

SerializableExternalizable的比较汇总:

序    号

区    别

Serializable

Externalizable

1

实现复杂度

实现简单,Java对其

有内建支持

实现复杂,

由开发人员自己完成

2

执行效率

所有对象由Java统一保存,

性能较低

开发人员决定哪个对象保存,

可能造成速度提升

3

保存信息

保存时占用空间大

部分存储,

可能造成空间减少


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值