Serializable 是 Java所提供的一个序列化接口,这里提到了序列化,那什么叫序列化和反序列化呢?
序列化就是将 Java 对象转换成二进制文件数据的过程。这样说可能不是很明白,举个例子:如果把一个房子比作一个对象,要把这个做房子搬到另外一个地方的话,直接挪动是不现实的,但是可以将房子拆成一个个小零件运输,到了目的地在组装成房子,这样就容易多了,这其中 “拆解” 的过程就是序列化,“重新组装” 就是反序列化。
说到这里,怎么实现序列化呢?
只需要在类的声明中指定一个类似下面的标识即可自动实现默认的序列化过程。
private static final long serialVersionUID = 51906712373232662L;
全部代码:
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 51906712373232662L;
public int userId;
public String userName;
public boolean isMale;
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
}
对象的序列化和反序列化只需要采用 ObjectOutputStream 和 ObjectInputStream 即可轻松实现,如下:
// 序列化过程,就是写的过程
User user = new User(0, "Jack", true);
ObjectOutputStream out;
{
try {
out = new ObjectOutputStream(new FileOutputStream("user.txt"));
out.writeObject(user);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 反序列化过程,就是读的过程
ObjectInputStream in;
User newUser;
{
try {
in = new ObjectInputStream(new FileInputStream("user.txt"));
newUser = (User) in.readObject();
in.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
现在有个问题,serialVersionUID 是用来辅助序列化和反序列化过程的,原则上序列化后的数据中 serialVersionUID 只有和当前类的 serialVersionUID 相同才能够正常地被反序列化。不用它行不行,答案:不行。
serialVersionUID 的详细工作机制是这样的:序列化的时候系统会把当前的 serialVersionUID 写入序列化的文件中(也可能是其他中介),当反序列化的时候系统回去检测文件中的 serialVersionUID ,看它是否和当前类的 serialVersionUID 一致,如果一致就说明序列化类的版本和当前的版本是相同的,这个时候可以成功反序列化;否则就说明当前类和序列化的类相比发生了变化,这个时候是无法反序列化的,会报错。
再简单的说就是:反序列化时如果当前类有所改变,比如增加或者删除了某些成员变量,那么系统就会重新计算当前类的 hash 值并把它赋值给 serialVersionUID ,这个时候当前类的 serialVersionUID 就和序列化的数据中心的 serialVersionUID 不一致,于是反序列化失败,程序 crash。所以,我们可以明显感觉到 serialVersionUID 的作用。
Serializable 就介绍到这里了,再加一点比较重要的知识点:静态成员变量属于类不属于对象。所以不会参与序列化的过程,其次使用 transient 关键字编辑的成员变量不参与序列化过程。
==============================================================================
我们在 Android Studio 中写了一个类 User 实现 Parcelable 接口
public class User implements Parcelable {
public int userId;
public String userName;
public boolean isMale;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
}
}
这个时候就会爆红,我们把鼠标放到 User 上面然后按住 "Alt + Enter"键会出现下图的情况,点击第一个 Add Parcelable Implementation
点击之后编辑器自动给我们写了序列化和反序列化过程,非常省事
我们看看全部代码:
import android.os.Parcel;
import android.os.Parcelable;
public class User implements Parcelable {
public int userId;
public String userName;
public boolean isMale;
protected User(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMale = in.readByte() != 0;
}
// 反序列化
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
// 内容描述
@Override
public int describeContents() {
return 0;
}
// 序列化
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(userId);
parcel.writeString(userName);
parcel.writeByte((byte) (isMale ? 1 : 0));
}
}
Parcelable 的方法说明
| 方法 | 功能 | 标记位 |
| — | — | — |
| createFromParcel(Parcel in) | 从序列化后的对象中创建原始对象 | |
| newArray(int size) | 创建指定长度的原始对象数组 | |