序列化是什么?为什么需要序列化?
1.序列化是什么?
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。
序列化分为两大部分:序列化和反序列化。
序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。
反序列化就是打开字节流并重构对象。
通俗的来讲:序列化是将对象存储为二进制格式。
2.为什么要把对象序列化?
序列化是将对象转换为容易传输的格式的过程,是为了解决在对对象流进行读写操作时所引发的问题。
对象序列化的两个使用场景:
- 对象持久化:将对象的状态持久化,比如存储到数据库中。
- 对象远程传输:将对象从一台计算机发送到另外一台计算机。
实现方式
Serializable接口
Serializable是java所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。
想要对一个对象实现序列化,只需要这个类实现Serializable接口(并声明SerializableUID,SerializableUID不是必需的,但是关于它的必要性下边会讲到)。
public class User implements Serializable{
private static final long SerializableUID =1L;
public int userId;
……
}
通过Serializable方式来实现对象的序列化和反序列化实现起来也很简单:只需要采用ObjectOutputStream和ObjectInputStream即可实现。
//序列化过程
User user = new User(0,"jack");
ObjectOutputStream out =new ObjectOutputStream(new FileOutputStream(cache.txt));
out.writeObject(user);
out.close();
//反序列化过程 (回复后的对象newUser和user的内容完全一样,但是两者并不是同一个对象)
ObjectInputStream in =new ObjectInputStream(new FileInputStream(cache.txt));
User newUser=(User)in.readObject();
in.close();
SerializableUID的必要性
即使我们不指定SerializableUID也可以实现序列化,那到底要不要指定呢?
回答:有必要指定,SerializableUID可以避免反序列化过程的失败。
SerializableUID是用来辅助序列化和反序列化过程的。原则上只有反序列化后的数据中的SerializableUID和当前类的SerializableUID相同才能正常的被反序列化。
SerializableUID的工作机制
- 序列化的时候系统会把当前类的SerializableUID写入序列化的文件中
- 反序列化的时候系统会去检测文件中的SerializableUID,看它是否和当前类的SerializableUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候就可以成功反序化;否则说明当前类和序列化好的类相比发生了某些变化(比如成员变量的数量,类型可能发生了变化),这个时候是无法正常反序列化的。
当我们手动的制定了SerializableUID之后,就可以很大程度上避免反序列化过程的失败(比如版本升级后,我们可能删除了某个成员变量也可能增加了一些成员变量,这个时候我们反序列化过程仍然能成功)。
如果类的机构发成了非常规性改变(比如修改了类名,修改了成员变量的类型),这时候尽管SerializableUID验证通过了,但反序列化过程还是会失败,因为类结构有了毁灭性的改变。
Parcelable接口
Parcelable是Android提供的新的序列化方式。Parcelable也是一个接口。只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。
//Parcelable接口使用
public class User implements Parcelabe{
public int userId;
public String userName;
public User(int userId,String userName){
this.userId=userId;
this.userName=userName;
}
public int describeCobtents(){
return 0;
}
public void writeToParcel(Parcel out ,int flags){
out.writeInt(userId);
out.writeStrin(userName);
}
public static final Parcelable.Creator<User> CREATOR =new Parcelable.Creator<User>(){
public User createFrromParcel(Parcel in){
return new User(in);
}
public User[] newArray(int size){
return new suer[size];
; }
};
private User(Parcel in){
userId=in.readInt();
userName=in.readString();
}
}
两者的区别及使用场景
Serializable和Parcelable都能实现序列化并且都可以用于Intent键的数据传递,那么二者如何选取呢?
- Serializable是Java提供的序列化接口,使用起来简单但是开销很大,因为序列化和反序列化过程需要大量的I/O操作;
- Parcelable虽然使用起来稍微麻烦一些,但是他的效率高,是Android推荐的序列化方式。
使用场景:
- 只进行序列化操作,用于应用内数据的传输则使用Parcelable,因为他效率高
- 需要持久化或网络传输则建议使用Serializable,因为Parcelable比较复杂。