赞
踩
对象的序列化也是有着特殊的应用场景的,我想大概有如下场景需要对象的序列化:
序列化方式:
Serializable是java提供的一个序列化的接口,这个接口是个空实现。为对象提供标准的序列化和反序列化操作。
定义一个类实现Serializable接口,然后声明个serialVersionUID即可。甚至serialVersionUID也不是必须的。我们不声明这个值也可以完成序列化,但是会对反序列化产生影响。
public class User implements Serializable {
private static final long serialVersionUID = 1L;
public String userName;
public int userId;
public boolean isMale;
public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
}
}
private void serializableTest() throws Exception { User user = new User(0, "Tom", true); //对象写入文件 ---序列化过程 ObjectOutputStream oos = new ObjectOutputStream(openFileOutput("cache.txt",MODE_PRIVATE)); oos.writeObject(user); oos.close(); // 对象读取 --- 反序列化过程 ObjectInputStream ois = new ObjectInputStream(openFileInput("cache.txt")); User newUser = (User) ois.readObject(); ois.close(); Log.i(TAG, "newUser:"+newUser.userName);//newUser:Tom Log.i(TAG, "newUser:"+newUser.userId);//newUser:0 Log.i(TAG, "newUser:"+newUser.isMale);//newUser:true }
1、serialVersionUID的工作机制:
序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中,当反序列化的时候系统会检测这个文件中的serialVersionUID是否和当前类的serialVersionUID一致,如果一致这个时候可以反序列化成功,否则就说明当前类和序列化的类相比发生了某些变化。比如成员变量的数量、类型可能发生了改变,这个时候是无法正常反序列化的,序列化异常(InvalidClassException ).
2、serialVersionUID手动指定区别1、手动指定serialVersionUID时:
这样序列化和反序列化时的serialVersionUID是相同的,因此可以正常反序列化。即使当类结构发生变化时,系统也会尽可能的恢复原有类结构,也不至于InvalidClassException 异常
2、未指定serialVersionUID的值时:
反序列化时当前类有所改变,比如增加或减少了某些成员变量,那么系统会重新计算当前类的hash值并把它赋值给serialVersionUID,这个时候当前类的serialVersionUID就和序列化数据中的serialVersionUID不一致,于是反序列化失败,程序就会出现crash。
所以当我们手动指定了serialVersionUID的值,就可以很大程度上避免了反序列化的失败。但是如果类结构发生了非常规性改变,比如修改了类名,修改了成员变量的类型,这个时候尽管serialVersionUID验证通过了,但是反序列化还是会失败,因为类结构发生了毁灭性的改变。
二者区别:
1L这种主要是用于区分系统版本号的,随着版本号的增加,可以改成2L、3L等。但程序很有可能升级版本,如果使用了1L、2L导致序列号不同,有可能第二版会不兼容第一版的程序,但是64位的哈希字段方式就可以,只要这个类本身没有修改过,两个相同的序列号都会指向同一个类。
1、Serializable 的原理是通过 ObjectInputStream 和 ObjectOutputStream 来实现的,整个序列化过程使用了大量的反射和临时变量,而且在序列化对象的时候,不仅会序列化对象本身,还需要递归序列化对象引用的其他对象。
1、在序列化过程中,如果实现序列化接口的类中定义了 writeObject 和 readObject 方法,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化。如果没有这样的方法,则默认调用的是 ObjectOutputStream 的 defaultWriteObject 方法和 ObjectInuputStream 的 defaultReadObject 方法。
2、如果实现序列化接口类中了定义writeReplace 和 readResovle 方法。这两个方法代理序列化的对象,可以实现自定义返回的序列化实例。通过它们我们可以实现对象序列化的版本兼容,在反序列化生成新的对象的时候会破坏单例,我们可以添加一个 readResolver 方法直接返回单例对象即可。例如【java设计模式】单例设计模式(Singleton)中第三小节。
ps:自定义序列化可对字段做特殊处理,例如实现序列化加密。
/** * Create by SunnyDay on 2019/03/31 */ public class User implements Parcelable { public int userId; public String userName; public boolean isMale; public Book book; public User(int userId, String userName, boolean isMale) { this.userId = userId; this.userName = userName; this.isMale = isMale; } protected User(Parcel in) { userId = in.readInt(); userName = in.readString(); isMale = in.readByte() != 0; book = in.readParcelable(Thread.currentThread().getContextClassLoader()); } 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 dest, int flags) { dest.writeInt(userId); dest.writeString(userName); dest.writeByte((byte) (isMale ? 1 : 0)); dest.writeParcelable((Parcelable) book, 0); } }
定义类实现Parcelable接口即可,根据编译器提示实现Parcelable接口中的方法即可,再根据提示实现CREATOR完成固定逻辑。
方法 | 功能 |
---|---|
createFromParcel(Parcel in) | 从序列化后的对象中创建原始对象 |
writeToParcel(Parcel dest, int flags) | 将当前对象写入序列化结构中,其中flags的标识有0或者1,为1标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0。 |
newArray(int size) | 创建指定长度原始类型数组。 |
User(Parcel in) | 从序列化后的对象中创建原始对象。此构造编译器提示帮你生成。 |
describeContents | 返回对象的内容描述,如果含有文件描述符返回1否则返回0,一般为0 |
在 User(Parcel in)中book是另一个可序列化对象(作为本类的成员),所以他的反序列化过程需要传递当前线程上下文的类加载器。否则报无法找到类的错误。
序列化方式 | 优点 | 缺点 | 使用场景 |
---|---|---|---|
Serializable | 使用简单、不需要手动去处理序列化和反序列化的过程 | 开销非常大,序列化和反序列化过程需要大量io操作 | 将对象序列化到设备中或者将对象序列化后通过网络传输 |
Parcelable | 效率高 | 使用起来麻烦、需要手动去处理序列化和反序列化的过程 | 内存上进行序列化 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。