Android序列化:Serializable和Parcelable

引言

首先要明白一个问题,什么是序列化?

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

SerializableParcelable都可以完成对象序列化的过程。下面就分别介绍一下两种序列化方法。

Serializable

Serializable是Java提供的一个序列化接口,它是一个空接口。使用Serializable进行序列化非常简单,需要序列化的类实现Serializable这个接口并且声明一个常量private static final long serialVersionUID就可以了。

public class User implements Serializable{
    private static final long serialVersionUID = 7382351359868556980L;

    private int age;
    private String name;

    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

然后就进行序列化和反序列化。

序列化:

        try{
            User user = new User(0,"Jack");
            FileOutputStream fs = new FileOutputStream("cache.txt");
            ObjectOutputStream out =  new ObjectOutputStream(fs);
            out.writeObject(user);
            out.close();
        }catch(Exception ex){
            ex.printStackTrace();
        }

反序列化:

        try{
            FileInputStream fs = new FileInputStream("cache.txt");
            ObjectInputStream in =  new ObjectInputStream(fs);
            User newUser = (User)in.readObject();
            in.close();
        }catch(Exception ex){
            ex.printStackTrace();
        }

上述代码演示了采用Serializable方式序列化对象的过程,很简单,但要注意的一点是一开始的user对象和后来的newUser对象虽然内容完全一样但是不是同一个对象。

serialVersionUID:
它其实也可以不设置,不设置的话系统会为我们自动生成

Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值

显式地定义serialVersionUID有两点好处
1)在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

2)当你序列化了一个类实例后,希望更改一个字段或添加一个字段,不设置serialVersionUID,所做的任何更改都将导致无法反序化旧有实例,并在反序列化时抛出一个异常。如果你添加了serialVersionUID,在反序列旧有实例时,新添加或更改的字段值将设为初始化值(对象为null,基本类型为相应的初始默认值),字段被删除将不设置。

Externalizable

他是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性

但是如果你只想隐藏一个属性,比如用户对象user的密码pwd,如果使用Externalizable,并除了pwd之外的每个属性都写在writeExternal()方法里,这样显得麻烦,可以使用Serializable接口,并在要隐藏的属性pwd前面加上transient就可以实现了。

关于transient可以参考这篇文章Java transient关键字使用小记

Parcelable

Parcelable是谷歌推荐的一种序列化方式。Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent和Binder所支持的数据类型,这样也就实现传递对象的功能了

从parcelable接口定义中,我们可以看到,实现parcelable接口,需要我们实现下面几个方法:

1.describeContents()
内容接口描述,默认返回0就可以;

2.writeToParcel ()
该方法将类的数据写入外部提供的Parcel中.即打包需要传递的数据到Parcel容器保存,以便从parcel容器获取数据。

3.静态的Parcelable.Creator接口,此接口有两个方法:
createFromParcel(): 从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层。
newArray() :创建一个类型为T,长度为size的数组,仅一句话(return new T[size])即可。方法是供外部类反序列化本类数组使用。

我们利用Android Studio可以很快地生成如下代码:

public class User implements Parcelable{
    private int age;
    private String name;

    protected User(Parcel in) {
        age = in.readInt();
        name = in.readString();
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeString(name);
    }
}

总结

Serializable方式在序列化和反序列化中需要大量I/0操作,会创建许多的临时对象,容易触发垃圾回收,效率较低

Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent和Binder所支持的数据类型,这样也就实现传递对象的功能了

所以Parcelable主要用于内存序列化上,而Parcelable的持久化存储不稳定,所以需要将对象序列化后存储到设备中或者通过网络传输时我们使用Serializable比较好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值