Android 序列化和反序列化

简介

  • 序列化:由于存在于内存中的变量都是暂时的,无法长期驻存,为了把对象的状态保持下来,把变量从内存中变成可存储或传输的过程就叫做序列化。
  • 反序列化:反序列化恰恰是序列化的反向操作,反过来,把变量内容从序列化的对象重新读到内存里就叫做反序列化。
  • Android中一个对象实现序列化操作,该类必须实现SerializableParcelable接口。

Serializable

Serializable 是 java 提供的一个序列化接口,它是一个空接口,专门为对象提供标准的序列化和反序列化操作,使用Serializable实现类的序列化比较简单,只要在类声明中实现 Serializable 接口即可,同时强烈建议声明序列化标识serialVersionUID 。

serialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化后的对象中serialVersionUID只有和当前类的serialVersionUID相同才能够正常被反序列化,也就是说序列化与反序列化的serialVersionUID必须相同才能够使序列化操作成功。实际上我们不声明serialVersionUID也是可以的,因为在序列化过程中会自动生成一个serialVersionUID来标识序列化对象。

import java.io.Serializable;

public class Person implements Serializable {
    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public static void main(String[] args) throws Exception {
    Person p = new Person();
    p.setId(1);
    p.setName("Tom");
    p.setAge(25);

    //序列化过程
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("p.txt"));
    oos.writeObject(p);
    oos.close();

    //反序列化过程
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("p.txt"));
    Person p2 = (Person) ois.readObject();
    System.out.println(p2);
    ois.close();
}
自定义序列化过程
  1. writeReplace():序列化时,首先系统会先调用writeReplace方法,在这个阶段,可以进行自己操作,将需要进行序列化的对象换成我们指定的对象, 一般很少重写该方法。

  2. writeObject():接着系统将调用writeObject方法,来将对象中的属性一个个进行序列化,我们可以在这个方法中控制住哪些属性需要序列化。

  3. readObject():反序列化时,系统会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,反序列化回来。然后通过readResolve方法,我们也可以指定系统返回给我们特定的对象可以不是writeReplace序列化时的对象,可以指定其他对象.

  4. readResolve():通过readResolve方法,我们也可以指定系统返回给我们特定的对象可以不是writeReplace序列化时的对象,可以指定其他对象,一般很少重写该方法。

package com.example.myapp;

import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;

public class Person implements Serializable {
    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    /**
     * 序列化时,
     * 首先系统会先调用writeReplace方法,在这个阶段,
     * 可以进行自己操作,将需要进行序列化的对象换成我们指定的对象.
     * 一般很少重写该方法
     */
    private Object writeReplace() throws ObjectStreamException {
        System.out.println("writeReplace invoked");
        return this;
    }

    /**
     * 接着系统将调用writeObject方法,
     * 来将对象中的属性一个个进行序列化,
     * 我们可以在这个方法中控制住哪些属性需要序列化.
     * 这里只序列化name属性
     */
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        System.out.println("writeObject invoked");
        out.writeObject(this.name == null ? "默认值" : this.name);
        out.writeObject(this.age);
        out.writeObject(this.id);
    }

    /**
     * 反序列化时,系统会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,
     * 反序列化回来.然后通过readResolve方法,我们也可以指定系统返回给我们特定的对象
     * 可以不是writeReplace序列化时的对象,可以指定其他对象.
     */
    private void readObject(java.io.ObjectInputStream in) throws IOException,
            ClassNotFoundException {
        System.out.println("readObject invoked");
        this.name = (String) in.readObject();
        this.age = (int) in.readObject();
        this.id = (int) in.readObject();
        System.out.println("name:" + name);
    }

    /**
     * 通过readResolve方法,我们也可以指定系统返回给我们特定的对象
     * 可以不是writeReplace序列化时的对象,可以指定其他对象.
     * 一般很少重写该方法
     */
    private Object readResolve() throws ObjectStreamException {
        System.out.println("readResolve invoked");
        return this;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public static void main(String[] args) throws Exception {
        Person p = new Person();
        p.setId(1);
//        p.setName("Tom"); // 不设置
        p.setAge(25);

        //序列化过程
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("p.txt"));
        oos.writeObject(p);
        oos.close();

        //反序列化过程
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("p.txt"));
        Person p2 = (Person) ois.readObject();
        System.out.println(p2);
        ois.close();

    }

输出信息:

writeReplace invoked
writeObject invoked
readObject invoked
got name:默认值
readResolve invoked
Person{id=1, name='默认值', age=25}

Parcelable

鉴于Serializable在内存序列化上开销比较大,而内存资源属于android系统中的稀有资源(android系统分配给每个应用的内存开销都是有限的),为此android中提供了Parcelable接口来实现序列化操作,Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如通过Intent在activity间传输数据。

package com.example.myapp.parcelable;

import android.os.Parcel;
import android.os.Parcelable;

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    /**
     * 当前对象的内容描述,一般返回0即可
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 将当前对象写入序列化结构中
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.id);
        dest.writeString(this.name);
        dest.writeInt(this.age);
    }

    /**
     * public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。
     */
    public static final Creator<User> CREATOR = new Creator<User>() {
        /**
         * 从序列化后的对象中创建原始对象
         */
        @Override
        public User createFromParcel(Parcel source) {
            User user = new User();
            user.id = source.readInt();
            user.name = source.readString();
            user.age = source.readInt();
            return user;
        }

        /**
         * 创建指定长度的原始对象数组
         */
        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };
}

Parcelable 与 Serializable 区别

  • 在使用内存的时候,ParcelableSerializable性能高,所以推荐使用Parcelable
  • Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
  • Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的 持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable

猜你喜欢

转载自blog.csdn.net/qq_14876133/article/details/82320373