Java序列化反序列化、Serializable、Parcelable 知识总结

前言

本博客对Java序列化反序列化、Serializable、Parcelable 知识的一个总结。在开发中我们发现Android中Intent传递对象有两种方法:一是Bundle.putSerializable(Key,Object),另一种是Bundle.putParcelable(Key,Object)。当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口。

一、java序列化、反序列化

推荐博文:java序列化、反序列化

1、定义:

Java序列化是指把Java对象转换为字节流的过程;而Java反序列化是指把字节流恢复为Java对象的过程。

2.为什么需要序列化与反序列化?

1)永久性保存对象,保存对象的字节序列到本地文件中;

2)通过序列化对象在网络中传递对象;

3)通过序列化在进程间传递对象。

3、如何实现Java序列化与反序列化

  • JDK类库中序列化API

    • java.io.ObjectOutputStream:对象输出流
      它的writeObject(Object obj)方法可以对object对象进行序列化,把得到的字节流写到一个目标输出流中。
    • java.io.ObjectInputStream:对象输入流,它的readObject()方法在输入流中读取字节流,再把它们反序列化成为一个对象。
  • 序列化、反序列化代码示例

    • 创建user对象:
    public class User  {
    // transient、static 修饰的成员变量将不会被序列化
    private transient String tag = null;
    public String name;
    public int id;

    public User(String name, int id) {
        this.name = name;
        this.id = id;
        }
    }
  • 对象序列化:
 file = new File("D:\\student.txt");
 User user = new User("张三", 22); 
 FileOutputStream fos = new  FileOutputStream(file);
 ObjectOutputStream oos = new ObjectOutputStream(fos);
 oos.writeObject(user);
 oos.flush();
 oos.close();
 fos.close();
  • 对象反序列化:
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
User user = (User) ois.readObject();
ois.close();

二、 Serializable

1、定义

Serializable 是Java用于标识可序列化定义的一个抽象空接口,对象实现了Serializable接口,标识该类可以被序列化、反序列化。Java 虚拟机会自动对该对象序列化、反系列化。

2、优势与劣势

1) 使用简单,很方便将对象存储到设备、网络传输。
2)开销很大,序列化、反序列化过程需要使用外部存储器,有大量的I/O操作。

三、 Parcelable

推荐博文:探索Android中的Parcel机制

1、定义

Parcelable是Android中提供的序列化方式。

2、优势与劣势

1) 整个读写全是在内存中进行,效率高,性能开销小。
2) android 官方推荐的序列化方式。
3) 使用稍微麻烦,需要自己写序列化、反序列化的相应代码。
4) 序列化内存中首选,序列化到存储存储、网络传输实现复杂麻烦。

2、实现Parcelable步骤

1)implements Parcelable 接口

2)重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel 容器中,将需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据。

3)重写describeContents方法,内容接口描述,默认返回0,如果有文件描述符返回1。

4)实例化静态内部对象CREATOR实现接口Parcelable.Creator

public static final Parcelable.Creator CREATOR

注:其中public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。需重写本接口中的两个方法:createFromParcel(Parcel in) 实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层,newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话即可(return new T[size]),供外部类反序列化本类数组使用。

简而言之:通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致。

Serializable、与Parcelable 的使用场景。

1)在内存序列化上,使用Parcelable序列化方式。

2)在将对象序列化到存储设备、网络上传输使用Serializable序列化方式。

代码实践:

  • Serializable
public class User implements Serializable {
    public String name;
    public int id;

    public User(String name, int id) {
        this.name = name;
        this.id = id;
    }
}
  • Parcelable
public class User2 implements Parcelable {

    public String name;
    public int id;

    public User2(String name, int id) {
        this.name = name;
        this.id = id;
    }


    /**
     * 反序列话的过程
     */
    public static final Creator CREATOR = new Creator() {

        // 从序列化的对象中创建原始对象
        @Override
        public User2 createFromParcel(Parcel in) {
            return new User2(in);
        }

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

    /**
     * 返回当前对象的内容描述
     *
     * @return 0 不返回 (几乎所有情况)、1 返回
     */
    @Override
    public int describeContents() {
        return 0;
    }


    /**
     * 对象序列化写到 Parcel 容器中
     *
     * @param dest  容器
     * @param flags 0 不返回(几乎所有情况)、 1 表示当前对象需要作为返回值返回,不能立即释放资源
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(id);
    }

    /**
     * 对象反序列化 从Parcel 容器中读取创建原始对象
     *
     * @param in 容器
     */
    protected User2(Parcel in) {
        name = in.readString();
        id = in.readInt();
    }
}

参考博客

https://www.cnblogs.com/renqingping/archive/2012/10/25/Parcelable.html

你可能感兴趣的:(android-面试,android)