序列化
序列化是将对象转化成特定规则二进制的数据,以便于进行传输,存储,进程间通信。反序列化,就是将特定规则二进制的数据转成对象。比如两个activity间可以用intent传输序列化的对象。Serializable和Parcelable都是用于序列化的接口。
- 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中,使用ObjectOutputStream和ObjectInputStream去做序列化和反序列化。将对象存储到外部存储器。
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对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将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后的变量不能被序列化;