zoukankan      html  css  js  c++  java
  • 两种序列化方式Serializable和Parcelable

    序列化(Serializable):将对象的状态信息转换为可以存储或传输形式的过程。简单来说,序列化就是将运行时的对象状态转换为二进制,然后保存到流,内存或者网络。

    在序列化期间,对象将其当前状态写入到临时或持久性存储区,之后,我们可以从存储区中读取或反序列化对象的状态,重新创建该对象。

    Serializable是Java提供的序列化接口,它是一个空接口,如下:

    public interface Serializable {
        
    }

    序列化的实现举例:

    public class Student implements Serializable {
        private static final long serialVersionUID = 123456789;
        private String mName;
        
        public String getName() {
            return mName;
        }
        
        public void setName(String name) {
            mName = name;
        }
    }

    Serializable序列化的方式比较简单,除了我们想要实现的内容,只需要添加一个serialVersionUID属性就行,该属性唯一标识一个可序列化的类,在反序列化时用来检查版本号是否一致,不一致会报错:InvalidClassException

     Serializable用来标识当前类可以被ObjectOutputStream序列化,可以被ObjectInputStream反序列化

    序列化对象:

    synchronized public static boolean saveObject(Object obj, String path) {
        if(null == obj) {
            return false;
        }
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream(path));
            oos.writeObject(obj);
            oos.close();
            return true;
        }catch(IOException e) {
            e.printStackTrace();
        }finally {
            if(oos != null) {
                try {
                    oos.close();
                }catch(IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    反序列化对象:

    @SuppressWarnings("unchecked ")
    synchronized public static <T> T readObject(String path) {
        ObjectInputStream ojs = null;
        try {
            ojs = new ObjectInputStream(new FileInputStream(path));
            return (T) ojs.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            close(ojs);
        }
        return null;
    }


    Parcelable是Android特有的序列化接口:

    public interface Parcelable {
        //writeToParcel() 方法中的参数,用于标识当前对象作为返回值返回
        //有些实现类可能会在这时释放其中的资源
        public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
    
        //writeToParcel() 方法中的第二个参数,它标识父对象会管理内部状态中重复的数据
        public static final int PARCELABLE_ELIDE_DUPLICATES = 0x0002;
    
        //用于 describeContents() 方法的位掩码,每一位都代表着一种对象类型
        public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;
    
        //描述当前 Parcelable 实例的对象类型
        //比如说,如果对象中有文件描述符,这个方法就会返回上面的 CONTENTS_FILE_DESCRIPTOR
        //其他情况会返回一个位掩码
        public int describeContents();
    
        //将对象转换成一个 Parcel 对象
        //参数中 dest 表示要写入的 Parcel 对象
        //flags 表示这个对象将如何写入
        public void writeToParcel(Parcel dest, int flags);
    
        //实现类必须有一个 Creator 属性,用于反序列化,将 Parcel 对象转换为 Parcelable 
        public interface Creator<T> {
    
            public T createFromParcel(Parcel source);
    
            public T[] newArray(int size);
        }
    
        //对象创建时提供的一个创建器
        public interface ClassLoaderCreator<T> extends Creator<T> {
            //使用类加载器和之前序列化成的 Parcel 对象反序列化一个对象
            public T createFromParcel(Parcel source, ClassLoader loader);
        }
    }

    实现了 Parcelable 接口的类在序列化和反序列化时会被转换为 Parcel 类型的数据 。

    Parcel 是一个载体,它可以包含数据或者对象引用,然后通过 IBinder 在进程间传递。

    实现 Parcelable 接口的类必须有一个 CREATOR 类型的静态变量,下面是一个实例:

    public class ParcelableGroupBean implements Parcelable {
    
        private String mName;
        private List<String> mMemberNameList;
        private User mUser;
    
        /**
         * 需要我们手动创建的构造函数
         * @param name
         * @param memberNameList
         * @param user
         */
        public ParcelableGroupBean(String name, List<String> 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<ParcelableGroupBean> CREATOR = new Creator<ParcelableGroupBean>() {
            /**
             * 反序列创建对象
             * @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();
            //反序列化时,如果User也是 Parcelable 的类,需要使用它的类加载器作为参数,否则报错无法找到类
            mUser = in.readParcelable(User.class.getClassLoader());
        }
    
    }

    可以看到,Serializable 的使用比较简单,创建一个版本号即可;而 Parcelable 则相对复杂一些,会有四个方法需要实现。

    一般在保存数据到 SD 卡或者网络传输时建议使用 Serializable 即可,虽然效率差一些,好在使用方便。

    而在运行时进行数据传递建议使用 Parcelable,比如 Intent,Bundle 等,Android 底层做了优化处理,效率很高。

  • 相关阅读:
    linux学习-----项目上线步骤
    linux学习-----数据库MySQL
    linux学习-----shell基础
    linux学习-----网络基础,网络相关命令,项目上线流程
    linux学习-----linux权限,sudo的使用
    linux学习-----开机启动项设置,ntp服务,防火墙服务,rpm服务,cron服务
    linux学习-----用户,用户组管理 网络设置 ssh服务
    linux学习-----vim编辑器的使用
    linux学习-----指令学习2 及练习
    linux学习-----指令学习1
  • 原文地址:https://www.cnblogs.com/chen-cai/p/9637251.html
Copyright © 2011-2022 走看看