Java序列化的总结

为什么要序列化与反序列化

当我们的应用需要从网络获取包括文本、图片、音频、视频等资源时,这些数据都会以二进制序列的形式在网络上传送。发送方需要把这些Java对象转换为字节序列,然后在网络上传送,接收方需要从字节序列中恢复出Java对象。使用序列化之后才能将对象保存在本地,也才能将对象在网络上传输。

什么是序列化与反序列化

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

序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。

反序列化:客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。

使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。

哪些场景需要序列化

永久性保存对象,保存对象的字节序列到本地文件中;
对象在网络中传递;
对象在 IPC 间传递。

序列化与反序列化如何实现

使用对象输入流ObjectOutputStream可将流转为对象,实现序列化;使用对象输入流ObjectInputStream读取对象,实现反序列化。

public static void main(String[] args) throws Exception {
                //序列化对象
        Student student = new Student();
        FileOutputStream fos=new FileOutputStream("F:"+File.separator+"TestFiles"+File.separator+"MyTest.txt");     
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(student);
        oos.close();
        
                //反序列化对象
        FileInputStream fis = new FileInputStream("F:"+File.separator+"TestFiles"+File.separator+"MyTest.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Student student2= (Student) ois.readObject();
        System.out.println(student2);
    }
Serializable 和 Parcelable 的区别
  • Serializeble 是 java 的序列化方式,Parcelable 是 Android 特有的序列化方式;

  • 在使用内存的时候,Parcelable 比 Serializable 性能高,所以推荐使用 Parcelable。

  • Serializable 在序列化的时候会产生大量的临时变量,从而引起频繁的 GC。

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

  • Serializeble 序列化的方式比较简单,直接集成一个接口就好了,而 parcelable 方式比较复杂,不仅需要集成 Parcelable 接口还需要重写里面的方法。

Serializable 有以下几个特点:
  • 可序列化类中,未实现 Serializable 的属性状态无法被序列化/反序列化
  • 也就是说,反序列化一个类的过程中,它的非可序列化的属性将会调用无参构造函数重新创建
  • 因此这个属性的无参构造函数必须可以访问,否者运行时会报错
  • 一个实现序列化的类,它的子类也是可序列化的
Parcelable 接口

实现了 Parcelable 接口的类在序列化和反序列化时会被转换为 Parcel 类型的数据 。
Parcel 是一个载体,它可以包含数据或者对象引用,然后通过 IBinder 在进程间传递。

实现Parcelable示例:

public class ParcelableGroupBean implements Parcelable {

    private String mName;
    private List mMemberNameList;
    private User mUser;

    /**
     * 需要我们手动创建的构造函数
     * @param name
     * @param memberNameList
     * @param user
     */
    public ParcelableGroupBean(String name, List memberNameList, User user) {
        mName = name;
        mMemberNameList = memberNameList;
        mUser = user;
    }

    /**
     * 1.内容描述
     * @return
     */
    @Override
    public int describeContents() {
        //几乎都返回 0,除非当前对象中存在文件描述符时为 1
        return 0;
    }

    /**
     * 2.序列化
     * @param dest
     * @param flags 0 或者 1
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mName);
        dest.writeStringList(mMemberNameList);
        dest.writeParcelable(mUser, flags);
    }

    /**
     * 3.反序列化
     */
    public static final Creator CREATOR = new Creator() {
        /**
         * 反序列创建对象
         * @param in
         * @return
         */
        @Override
        public ParcelableGroupBean createFromParcel(Parcel in) {
            return new ParcelableGroupBean(in);
        }

        /**
         * 反序列创建对象数组
         * @param size
         * @return
         */
        @Override
        public ParcelableGroupBean[] newArray(int size) {
            return new ParcelableGroupBean[size];
        }
    };

    /**
     * 4.自动创建的的构造器,使用反序列化得到的 Parcel 构造对象
     * @param in
     */
    protected ParcelableGroupBean(Parcel in) {
        mName = in.readString();
        mMemberNameList = in.createStringArrayList();
        //反序列化时,如果熟悉也是 Parcelable 的类,需要使用它的类加载器作为参数,否则报错无法找到类
        mUser = in.readParcelable(User.class.getClassLoader());
    }

}
如何选择哪种序列化方式

一般在保存数据到 SD 卡或者网络传输时建议使用 Serializable 即可,虽然效率差一些,好在使用方便。
而在运行时数据传递时建议使用 Parcelable,比如 Intent,Bundle 等,Android 底层做了优化处理,效率很高。

为什么Activity间传递对象需要序列化

activity间传递对象使用intent,Intent 在启动其他组件时,会离开当前应用程序进程,进入 ActivityManagerService 进程 – intent.prepareToLeaveProcess()。 这也就意味着,Intent 所携带的数据要能够在不同进程间传输。

参考:https://blog.csdn.net/weixin_47933729/article/details/112389099

你可能感兴趣的:(Java序列化的总结)