笔记:Android中的序列化方案

什么是序列化

  • 序列化:将数据结构或对象转换成二进制串的过程 常用于进程间或者网络通讯
  • 反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
  • 持久化:将数据结构或者对象 保存到硬盘 等其他存储设备

常用的序列化方案

  • Serializable 与 Externalizable

    • 实现 Serializable:

        class User implements Serializable {
          public String name;
          public int age;
          public User(String name, int age) {
              this.name = name;
              this.age = age;
          }
        
      
          @Override
          public String toString() {
              return "User{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
    • 实现 Externalizable:

       static class User implements Externalizable {
          //必须要一个public的无参构造函数 否则无法正常反序列化
          public User(){}
      
          public User(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String name;
          public int age;
      
      
          @Override
          public String toString() {
              return "User{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      
          @Override
          public void writeExternal(ObjectOutput out) throws IOException {
              out.writeObject(name);
              out.writeInt(age);
          }
      
          @Override
          public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            name = (String)in.readObject();
            age = in.readInt();
          }
      }   
      
    • Serializable的使用常见问题:

      1. 不加 serialVersionUID 与serialVersionUID的作用
      serialVersionUID 通常用于对象的版本控制 如果在数据结构发生改变时 会出现反序列化失败
      

      eg:先使用序列化 存储了一个对象


      image.png
       static class User implements Serializable {
       public User(String name, int age) {
           this.name = name;
           this.age = age;
       }
      
       public String name;
       public int age;
       //新增nickName 字段
       public String nickName;
      
       @Override
       public String toString() {
           return "User{" +
                   "name='" + name + '\'' +
                   ", age=" + age +
                   ", nickName=" + nickName +
                   '}';
         }
      }
      

      再读一次序列化文件,哦吼翻车:


      修改数据结构后读取序列化文件.png

      解决方式:加上 serialVersionUID


      加上serialVersionUID后.png
      2. 部分字段不需要序列化 使用transient关键字
      static class User implements Serializable {
      
        public User(){
            System.out.println("=============");
        }
        public User(String name, int age) {
            System.out.println("==============");
            this.name = name;
            this.age = age;
        }
      
        public String name;
        public int age;
      
        public transient String nickName;
      
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", nickName=" + nickName +
                    '}';
        }
      }
      public static void main(String[] args) {
        trasientTest();
      }
      
      private static void trasientTest() {
        User user = new User("salt fish", 18);
        user.nickName = "芭比龙";
        System.out.println("1: " + user);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream oos = null;
        byte[] userData = null;
        try {
            oos = new ObjectOutputStream(out);
            oos.writeObject(user);
            userData = out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
      
      
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new ByteArrayInputStream(userData));
            user = (User)ois.readObject();
            System.out.println("反序列化后 2: " + user);
        } catch (Exception e) {
            e.printStackTrace();
        }
      }
      打印结果:
      1: User{name='salt fish', age=18, nickName=芭比龙}
      反序列化后 2: User{name='salt fish', age=18, nickName=null}
      
      3. 序列化的类中有未序列化的成员 时会序列化失败 必须成员实现序列化接口
      4. 类序列化但是父类未序列化
         static class Person{
         private String sex;
         private int id;
      
         public Person() {
         }
      
         public Person(String sex, int id) {
             this.sex = sex;
             this.id = id;
         }
      
         public String getSex() {
             return sex;
         }
      
         public void setSex(String sex) {
             this.sex = sex;
         }
      
         public int getId() {
             return id;
         }
      
         public void setId(int id) {
             this.id = id;
         }
      
         @Override
         public String toString() {
             return "Person{" +
                     "sex='" + sex + '\'' +
                     ", id=" + id +
                     '}';
         }
      }
      
      static class User extends Person implements Serializable {
         public User(String name, int age,String sex,int id) {
             super(sex,id);
             this.name = name;
             this.age = age;
      
         }
      
         public User(){
             super();
         };
      
      
         public String name;
         public int age;
         //重写方法
         private void writeObject(ObjectOutputStream out) throws IOException {//不是重写父类的方案
             out.defaultWriteObject();
             out.writeObject(getSex());
             out.writeInt(getId());
         }
        //重写方法
         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
             in.defaultReadObject();
             setSex((String)in.readObject());
             setId(in.readInt());
         }
      
      
         @Override
         public String toString() {
             return "User{" +
                     "name='" + name + '\'' +
                     ", age=" + age +
                     "} " + super.toString();
         }
      }
      
      5. 父类可序列化 子类不想序列化
         static class Person implements Serializable {
         private static final long serialVersionUID = 5850510148907441688L;
         private String sex;
         private int id;
      
         public Person() {
         }
      
         public Person(String sex, int id) {
             this.sex = sex;
             this.id = id;
         }
      
         public String getSex() {
             return sex;
         }
      
         public void setSex(String sex) {
             this.sex = sex;
         }
      
         public int getId() {
             return id;
         }
      
         public void setId(int id) {
             this.id = id;
         }
      
         @Override
         public String toString() {
             return "Person{" +
                     "sex='" + sex + '\'' +
                     ", id=" + id +
                     '}';
         }
      }
      
      static class User extends Person {
         public User(String name, int age, String sex, int id) {
             super(sex, id);
             this.name = name;
             this.age = age;
      
         }
      
      
         public String name;
         public int age;
      
      
         @Override
         public String toString() {
             return "User{" +
                     "name='" + name + '\'' +
                     ", age=" + age +
                     "} " + super.toString();
         }
      }
      
      static class User1 extends Person {
         public User1(String name, int age, String sex, int id) {
             super(sex, id);
             this.name = name;
             this.age = age;
      
         }
      
      
         public String name;
         public int age;
         //子类不想被序列化的处理方式
         private void writeObject(java.io.ObjectOutputStream out) throws IOException {
             throw new NotSerializableException("Can not serialize this class");
         }
      
         private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
             throw new NotSerializableException("Can not serialize this class");
         }
      
         private void readObjectNoData() throws ObjectStreamException {
             throw new NotSerializableException("Can not serialize this class");
         }
      
      
         @Override
         public String toString() {
             return "User{" +
                     "name='" + name + '\'' +
                     ", age=" + age +
                     "} " + super.toString();
         }
      }
      
      
      6. 序列化单例类
      class Singleton implements Serializable{
         public static Singleton INSTANCE = new Singleton();
         private Singleton(){}
         //这里返回单例实例
         private Object readResolve(){
           return INSTANCE;
         }
      }
      
  • Parcelable

        class Person() : Parcelable{
          private  var name :String = ""
          private  var sex:Int = 0
          constructor(parcel: Parcel) : this() {
          }
    
          override fun writeToParcel(p0: Parcel?, p1: Int) {
              p0?.writeString(name)
              p0?.writeInt(sex)
          }
    
          override fun describeContents(): Int {
              return 0
          }
    
          companion object CREATOR : Parcelable.Creator {
              override fun createFromParcel(parcel: Parcel): Person {
                  return Person(parcel)
              }
    
              override fun newArray(size: Int): Array {
                  return arrayOfNulls(size)
              }
          }
    
      }
    
  • 两者对比

image.png
  • QA

  1. 反序列化后的对象,需要调用构造函数重新构造吗
    答:不需要 直接由Object强转

  2. 序列前的对象与序列化后的对象是什么关系?是("=="还是equal?是浅复制还是
    深复制?)
    答:深复制,枚举类型除外 枚举类型只会存储他的name在反序列化时通过valueOf找到对应的枚举

  3. Android里面为什么要设计出Bundle而不是直接用Map结构
    答:bundle 内部适用的是 ArrayMap, ArrayMap 相比 Hashmap 的优点是, 扩容方便, 每次扩容是原容量的一半, 在[百量] 级别, 通过二分法查找 key 和 value (ArrayMap 有两个数组, 一个存放 key 的 hashcode, 一个存放 key+value 的 Entry) 的效率要比 hashmap 快很多, 由于在内存中或者 Android 内部传输中一般数据量较小, 因此用 bundle 更为合适

4.Android 中 intent/bundle 的通信原理以及大小限制?
答: Android 中的 bundle 实现了 parcelable 的序列化接口, 目的是为了在进程间进行通讯, 不同的进程共享一片固定大 小的内存, parcelable 利用 parcel 对象的 read/write 方法, 对需要传递的数据进行内存读写, 因此这一块共享内存不能 过大

你可能感兴趣的:(笔记:Android中的序列化方案)