likes
comments
collection
share

JDK本身提供了Serializable序列化接口,为什么还要使用 Parcelable?破案了

作者站长头像
站长
· 阅读数 17

最近有个公众号粉丝和我聊了聊他面试的经历,一个刚入坑Android两年的新人,由于异地的原因视频面试,而面试官只问了一个问题:“JDK本身提供了Serializable序列化接口,为什么还要使用 Parcelable?”,结果他一时语塞面试OVER。说实话听到这个问题,我也有些懵逼,平时忙着研究各种组件、什么高可用框架,可真要回头对Java基础知识较起真,发现自己的技术债欠的太多,所以和大家一起复习一下Java序列化知识。

回顾

什么是序列化?

首先我们要了解什么是序列化?序列化是将对象的状态信息转换为可以存储或传输的形式的过程,序列化最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。

就相当于我们现在要把埃菲尔铁塔完全一摸一样的搬到北京,实现这个过程就是序列化的过程。我们需要给埃菲尔铁塔的每个部件都打上标记,这个钢筋部件原来在哪个位置,搬到北京后仍然要在对应的位置。这就是将埃菲尔铁塔序列化了之后传输(运输)到北京。而反序列化自然就是利用运到北京的部件根据标记信息还原的过程。

Serializable的原理

那么JDK当中实现的Serializable序列化接口是如何将一个对象进行序列化的?

static class SerializableTest implements Serializable {
        int i;
        long j;

        public SerializableTest(int i, int j) {
            this.i = i;
            this.j = j;
        }

        @Override
        public String toString() {
            return "SerializableTest{" +
                    "i=" + i +
                    ", j=" + j +
                    '}';
        }
}


@Test
public void testSerialible() throws IOException, ClassNotFoundException {
        SerializableTest serializableTest = new SerializableTest(1, 2);
        //序列化
        ObjectOutputStream os = new ObjectOutputStream(
            new FileOutputStream("SerializableTest"));
        os.writeObject(serializableTest);
        os.close();

        //反序列化
        ObjectInputStream is = new ObjectInputStream(new FileInputStream("SerializableTest"));
        SerializableTest serializableTest1 = (SerializableTest) is.readObject();
        System.out.println(serializableTest1);
}

对于JVM来说,要进行持久化的类必须要有一个标记,只有持有这个标记JVM才允许类创建的对象可以通过其IO系统转换为字节数据,从而实现持久化,而这个标记就是Serializable接口。而在反序列化的过程中则需要使用serialVersionUID来确定由哪个类来加载这个对象,如果我们在序列化中没有显示地声明serialVersionUID,则序列化运行时将会根据该类的各个方面计算该类默认的serialVersionUID值。 但是,Java官方强烈建议所有要序列化的类都显示地声明serialVersionUID字段,因为如果高度依赖于JVM默认生成serialVersionUID,可能会导致其与编译器的实现细节耦合,为了保证跨不同Java编译器实现的serialVersionUID值的一致,实现Serializable接口的必须显示地声明serialVersionUID字段。

总之实现了Serializable接口就相当于给类打上了一个标记,JVM就能够对类对象信息按照(Serializable)规则记录,而反序列化就按照规则解析即可。

Parcelable的原理

public class MyParcelable implements Parcelable {
      private int mData;
 
        public int describeContents() {
          return 0;
      }
 
      //序列化
      public void writeToParcel(Parcel out, int flags) {
          out.writeInt(mData);
      }
      //反序列化
      public static final Parcelable.Creator<MyParcelable> CREATOR
              = new Parcelable.Creator<MyParcelable>() {
          public MyParcelable createFromParcel(Parcel in) {
              return new MyParcelable(in);
          }
 
          public MyParcelable[] newArray(int size) {
              return new MyParcelable[size];
          }
      };
      
      private MyParcelable(Parcel in) {
          mData = in.readInt();
      } 

我们通过Serializable的使用可以发现,Serializable需要使用IO对序列化数据直接写入到文件当中。而Parcelable是android特有的序列化方式,我们在开发中可能并不需要将数据保存到文件当中,只在内存中进行传输使用,此时使用Parcelable将更为高效,因为Parcelable依赖于Parcel,Parcel的意思是包装,实现原理是在内存中建立一块共享数据块,序列化和反序列化均是操作这一块的数据,而不像Serializable需要使用IO。

JDK本身提供了Serializable序列化接口,为什么还要使用 Parcelable?破案了

对比

  • Serializable是java序列化的方式,存取的过程有频繁的IO,性能较差,但是实现简单。
  • Parcelable是android序列化的方式,采用共享内存的方式实现用户空间和内核空间的交换,性能很好,但是实现方式比较复杂。
  • Serializable可以持久化存储,Parcelable是存储在内存中的,不能持久化存储。

今日分享到此结束,对你有帮助的话,点个赞再走呗,好像写的有点浅,大家凑合看下吧,下期更精彩~

关注公众号:Android老皮 解锁  《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版

内容如下

1.Android车载应用开发系统学习指南(附项目实战) 2.Android Framework学习指南,助力成为系统级开发高手 3.2023最新Android中高级面试题汇总+解析,告别零offer 4.企业级Android音视频开发学习路线+项目实战(附源码) 5.Android Jetpack从入门到精通,构建高质量UI界面 6.Flutter技术解析与实战,跨平台首要之选 7.Kotlin从入门到实战,全方面提升架构基础 8.高级Android插件化与组件化(含实战教程和源码) 9.Android 性能优化实战+360°全方面性能调优 10.Android零基础入门到精通,高手进阶之路

敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔