序列化 : Serializable 与 Parcelable ( 上 )

序列化

想要在intent上传输对象的时候,直接传输是做不到的,需要对这个对象处理一下,而这个处理的过程,就叫做序列化。

关于序列化的定义,百度百科这样定义:

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。

比如说内存中有一组的对象集合,我们想要把这里的数据持久的保存下来。

而序列化,就是将对象保存成一连串字节描述的过程;相反,反序列化,就是将这一连串的字节描述恢复成对象的过程。

我是学Android的嘛,序列化在Android中可以用在把对象在网络上传输、intent意图传递等。

目前准备学习的序列化有两个,分别是Java的Serializable接口,还有Android特有的Parcelable接口,今天先着手一个较为简单的serializable接口。

Serializable:表示将一个对象转化成可存储或者可传输的状态,序列化之后的对象可以在网络上进行传输,也可以存储在本地。

Parcelable:将一个完整的对象进行分解,而分解后的每一个部分都是Intent所能支持的数据类型,因此实现传递对象的功能。

 

关于Serializable和Parcelable的两种方式,如何选择?

关于两者,先来看看它两个之间的区别:

1. Serializable是通过使用IO流的形式将数据读写入在硬盘上;而Parcelable则是在内存中直接进行读写。

2. Serializable在序列化的过程中会产生大量的临时文件,所以会产生频繁GC;Parcelable是以IBinder为载体,在内存中开销较小。

3. 因为Serializable是在磁盘中,所以它是数据持久化的;而Parcelable是在内存中,所以它不是。

 

从上面来看,Parcelable的效率要比Serializable高一些,一般情况下都是使用Parcelable,那么什么时候使用Serializable呢?

Parcelable不能使用在要将数据存储在磁盘上的情况,因为在外界有变化的情况下,Parcelable不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable 。

 

Serializable的用法

Serializable是Java所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化。

我们先将对象实现这个空接口,紧接这生成它所对应的 serialVersionUID 。

public class Girl implements Serializable {

    private static final long serialVersionUID = -7684134237751913941L;
    private String name;
    private int birth;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getBirth() {
        return birth;
    }
    public void setBirth(int birth) {
        this.birth = birth;
    }

}

serialVersionUID 一共有两种实现,一种是默认的。

private static final long serialVersionUID = 1L;

另一种是根据包名、类名、参数、返回值等因素,生成一个64位哈希字段,是一个唯一值。

private static final long serialVersionUID = -7684134237751913941L;

 

先来看序列化:

    private static void serializableGirl() throws IOException {
        Girl girl = new Girl();
        girl.setBirth(1997);
        girl.setName("Seas");
        ObjectOutputStream oos = new ObjectOutputStream(
                             new FileOutputStream(
                         new File("/Users/suyichen/workspace/Project/EclipseWork/girl.txt")));
        oos.writeObject(girl);
        System.out.println("序列化 success");
    }

对象的输出流,将对象存入了指定的目录中。其中的 oos.writeObject(girl) 将girl这个对象先进行序列化,然后把序列化得到的字节序列写入到目标输出流中。

看,已经在我的指定目录下生成了文件。

 

再来看反序列化:

    private static Girl deserializeGirl() throws Exception{
        ObjectInputStream ois = new ObjectInputStream(
                             new FileInputStream(
                          new File("/Users/suyichen/workspace/Project/EclipseWork/girl.txt")));
        Girl girl = (Girl) ois.readObject();
        System.out.println("反序列化 success");
        return girl;
    }

对象输入流,ois.readObject() 方法将指定输入流中读取字节序列,再将它转化成为对象。

 

注意:恢复后的对象和之前的对象虽然内容是完全一样的,但两者并不是同一个对象。

 

serialVersionUID

当序列化的时候,系统会把当前类的 serialVersionUID 写入到序列化的文件中去;当反序列化的时候,系统再去检测 serialVersionUID ,如果它与当前类的 serialVersionUID 一致,则证明之前序列化时类的版本和现在反序列化的版本相同,这时候可以成功的反序列化。

因为上面说到,serialVersionUID 是根据根据包名、类名、参数、返回值等因素,生成一个64位哈希字段,是一个唯一值,一旦包名、类名、参数有变化,再次生成 serialVersionUID 的话,serialVersionUID 肯定是不同的。

假如我们指定了 serialVersionUID 的值,并且更改了一些成员变量,这时候,我们仍能反序列化成功,程序仍能最大限度恢复数据。

如果不去指定 serialVersionUID 的值,反序列时当前类有变化,那么系统就会自动重新计算当前类的 serialVersionUID ,这时候当前类的 serialVersionUID 就与序列化的数据中 serialVersionUID 不同,然后反序列化失败,程序crash。

 

不参与序列化的两种情况

1. 静态成员变量。因为静态成员变量是属于类的,而并非属于对象。

2. 用transient关键字标记的成员变量。

 

参考文献

https://www.jianshu.com/p/af2f0a4b03b5

https://blog.csdn.net/u013870094/article/details/82765907

https://www.jianshu.com/p/a8fc2616badc

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值