Android 序列化Serializable、Parcelable

本文介绍了序列化和反序列化的概念,详细对比了Java提供的Serializable接口与Android提供的Parcelable接口的特点与应用场景,并提供了具体的实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

序列化

序列化是将对象转化成特定规则二进制的数据,以便于进行传输,存储,进程间通信。反序列化,就是将特定规则二进制的数据转成对象。比如两个activity间可以用intent传输序列化的对象SerializableParcelable都是用于序列化的接口。

  • Serializable: java提供,代码简单但低效,实现这个借口只需要(可选)声明一个long类型serialVersionUID
  • Parcelable: android提供,代码复杂但高效,需要实现较多方法。

Serializable

前文提及,这货很简单,你只要写一个(甚至不写)serialVersionUID 就可以跑了。

private static final long serialVersionUID = 1L; // 定义序列化ID 

这个serialVersionUID顾名思义,就是序列化版本id,这个id决定了反序列化能否成功,我们可以这样理解,JVM将对象序列化的过程中,会将serialVersionUID 插入到生成的二进制文件,然后可能保存下来了。
过了很久,要反序列化时又会取出这个对象,比较JVM当前对象与反序列化出的对象,情况如下:

  • serialVersionUID与当前对象声明的serialVersionUID 不一致,那么程序就会抛出InvalidCastException异常。
  • 如果serialVersionUID一致,但是代码较小改动,新增的属性会被赋值为默认,比如 int=0,boolean=false。删减的属性自然就没了。
  • 如果类的结构变化了(类名变了,属性名变了),也会抛出InvalidCastException异常。

如果你实现Serializable的类没有声明这个serialVersionUID,那么JVM会默认添加serialVersionUID,它的值存为该类的hashCode 值,所以,在正常情况下我们需要去写这个serialVersionUID

在android中,使用ObjectOutputStreamObjectInputStream去做序列化和反序列化。将对象存储到外部存储器。

bundle.putSerializable("key", class1);

如上,就可以用intent传输对象了。

Parcelable

实现该接口能通过Parcel类来完成对象写入和恢复,及序列化和反序列化。实现Parcelable必须有一个实现Parcelable.Creator接口的非静态的成员变量

来源:android.os.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();
     }
 }

我们自己实现一个Man类。

 public class Man implements Parcelable {
        public String name;
        public int age;
        public float height;
        //内容描述接口,可以不理睬
        @Override
        public int describeContents ( ) { return 0; }
        //将你的对象映射成Parcel对象
        @Override
        public void writeToParcel ( Parcel dest, int flags ) {
                dest.writeString ( this.name );
                dest.writeInt ( this.age );
                dest.writeFloat ( this.height );
        }

        public Man ( ) {}

        protected Man ( Parcel in ) {
                this.name = in.readString ( );
                this.age = in.readInt ( );
                this.height = in.readFloat ( );
        }

        public static final Parcelable.Creator< Man > CREATOR = new Parcelable.Creator< Man > ( ) {
                //反序列化成对象
                @Override
                public Man createFromParcel ( Parcel source ) {return new Man ( source );}

                @Override
                public Man[] newArray ( int size ) {return new Man[ size ];}
        };
}

这是一个我们自己定义的Man类。我们对其进行解释,通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcelParcel对象映射成你的对象。也可以将Parcel看成是一个,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致。

序列化可以进行传输和存储,基本有:

  • 当你想把的内存中的对象保存到一个文件中或者数据库中
  • 当你想在网络上传送对象
  • 当你想通过远程方法调用对象的时候;

Code

intent 传输

Intent intent = new Intent(this, Activity2.class);
     Bundle bundle = new Bundle();                                                                 bundle.putSerializable("key", class1);

注:
a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
c) static,transient后的变量不能被序列化;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值