https://www.cnblogs.com/yezhennan/p/5527506.html
https://blog.csdn.net/wangchunlei123/article/details/51345130
1.序列化的目的
(1).永久的保存对象数据(将对象数据保存在文件当中,或者是磁盘中
(2).通过序列化操作将对象数据在网络上进行传输(由于网络传输是以字节流的方式对数据进行传输的.因此序列化的目的是将对象数据转换成字节流的形式)
(3).将对象数据在进程之间进行传递(Activity之间传递对象数据时,需要在当前的Activity中对对象数据进行序列化操作.在另一个Activity中需要进行反序列化操作讲数据取出)
(4).序列化对象的时候只是针对变量进行序列化,不针对方法进行序列化.
(5).在Intent之间,基本的数据类型直接进行相关传递即可,但是一旦数据类型比较复杂的时候,就需要进行序列化操作了.
1.Serializable接口
Serializable接口是Java提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。数据的持久化。使用Serializable来实现的对象的序列化相当简单,只需要在类的生命中指定一个类似相面的标识即可自动实现默认的序列化过程。
private static final long serialVersionUID=871238749032;
完整的对象序列化代码示例如下:
//Model
public class User implements Serializable{
private static final long serialVersionUID=871238749032;
public int userId;
public String userName;
public String password;
}
//序列化到本地
User user=new User(0,"wcl_android@163.com","123456");
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("user.obj"));
out.writeObject(user);
out.close;
//反序列化
ObjectInputStream in=new ObjectInputStream(new FileInputStream("user.obj"));
User user=(User)in.readObject();
in.close();
原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。
序列化的时候系统会把当前类的serialVersionUID写入序列化的二进制文件中,
当反序列化的时候系统会检测文件中的serialVersionUID是否和当前类的serialVersionUID一致,
如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;
否则说明当前类和反序列化的类相比发生了某些变化,比如成员变量的数量、类型发生了变化,这个时候是无法正常反序列化的。
当然,我们还需要考虑一种情况,如果类结构发生了非城规改变,比如修改了类名,修改了成员变量的类型,这个时候尽管serialVersionUID验证通过了,但是反序列化过程仍然会失败,因为类的结构有了毁灭性的改变,根本无法从老版本的数据中还原出一个新的类结构的对象。
对于使用序列化还有两点需要注意:
1.静态成员变量属于类不属于对象,所以不参与序列化过程
2.用transient关键字标记的成员变量不参与序列化过程
2.Parcelable接口
Parcelable接口是Android SDK提供的一种专门用于Android应用中对象的序列化和反序列化的方式,相比于Seriablizable具有更好的性能。实现Parcelable接口的对象就可以实现序列化并可以通过Intent和Binder传递。
下面是一个完成的实现了Parcelable接口的类
public class User implements Parcelable{
public int userId;
public String userName;
public String password;
public Book book;
public User(int userId,String userName,String password,Book book){
this.userId=userId;
this.userName=userName;
this.password=password;
this.book=book;
}
public int describeContents(){
//几乎所有情况都返回0,仅在当前对象中存在文件描述符时返回1
return 0;
}
public void writeToParcel(Parcel out,int flags){
out.writeInt(userId);
out.writeString(userName);
out.writeString(password);
out.writeParcelable(book,0);
}
public static final Parcelable.Creator<User> CREATOR=new Parcelable.Creator<User>(){
public User createFromParcel(Parcel in){
return new User(in);
}
public User[] newArray(int size){
return new User[size];
}
}
private User(Parcel in){
userId=in.readInt();
userName=in.readString();
password=in.readString(); book=in.readParcelable(Thread.currentThread().getContextClassLoader());
}
}
看起来比Serializable方式复杂太多。我们使用表格把Parcelable方式的相关方法进行说明
方法 | 功能 | 标记位 |
---|---|---|
createFromParcel(Parcel in) | 从序列化后的对象中创建原始对象 | |
newArray(int size) | 创建指定长度的原始对象数组 | |
User(Parcel in) | 从序列化后的对象中创建原始对象 | |
writeToParcel(Parcel out,int flags) | 将当前对象写入序列化结构中 | PARCALABLE_WRITE_RETURN_VALUE |
describeContents | 返回当前对象的内容描述,几乎所有情况都返回0,仅在当前对象中存在文件描述符时返回1 | CONTENTS_FILE_DESCRIPTOR |
既然Parcelable和Serializable都可以实现序列化并且可以用于Intent间的数据传递,那么两者有什么区别呢?
区别 | Serializable | Parcelable |
---|---|---|
所属API | JAVA API | Android SDK API |
原理 | 序列化和反序列化过程需要大量的I/O操作 | 序列化和反序列化过程不需要大量的I/O操作 |
开销 | 开销大 | 开销小 |
效率 | 低 | 很高 |
使用场景 | 序列化到本地或者通过网络传输 | 内存序列化 |