序列化:将数据结构或对象转换成二进制串的过程。
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
Parcelable 与 Serializeable 的区别
Serializable | Parcelable |
---|---|
通过IO对硬盘操作,速度较慢 | 直接在内存操作,效率高,性能好 |
记录全类名、属性的类型、属性的值、属性名等信息 | 只记录属性的值信息,即占用的空间更少 |
大小不受限制 | 一般不能超过1M,修改内核也只能4M |
大量使用反射,产生内存碎片 | 不存在反射 |
Serializable.java
/*
* @author unascribed
* @see java.io.ObjectOutputStream
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutput
* @see java.io.ObjectInput
* @see java.io.Externalizable
* @since JDK1.1
*/
public interface Serializable {
}
Serializable是空的接口,一般用来做标记。如果一个类实现该接口,就是对这个类打上了标记,可以通过ObjectOutputstream进行写,调用writeObject通过流的方式写到文件中,如果没有这个标记就会抛出异常。ObjectOutputStream底层也是通过反射来获取对象的各个属性的名字、属性的值等
Serializable序列化会把一个对象的所有属性信息完整的记录下来(记录全类名、属性的类型、属性的值、属性名)
Parcelable.java
* 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();
* }
* }
*/
public interface Parcelable {
Parcelable进行序列化的时候,会调用writeToParcel()方法,把数据记录到Parcel中,Parcelable只记录属性的值,数据保存在内存中,数据不能持久化,占用的内存空间肯定比Serializable少。
Parcelable序列化和反序列化读取顺序必须一样
实现Serializable接口进行序列化不需要调用里面的方法进行序列化和反序列化,但是实现Parcelable接口进行序列化需要调用Parcelable中的方法进行序列化
Parcelable不需要借助IO,效率会更高,但是会更复杂些,需要自己实现
有关序列化的几个问题
什么是serialVersionUID?如果你不定义这个,会发生什么?
假如你有一个类,它序列化并存储在持久性中,然后修改了该类以添加新字段,如果对已序列化的对象进行反序列化,会发生什么情况?
答:serialVersionUID是一个private static final long类型的ID
,当它被印在对象上,它通常是对象的哈希码,你可以使用serialver这个JDK工具来查看序列化对象的serialVersionUID。serialVersionUID用于对于的版本控制
,也可以在类文件种指定serialVersionUID。不指定serialVersionUID的后果是,当你添加或修改类中的任何字段时,则已序列化类将无法恢复,因为为新类和旧序列化对象生产的serialVersionUID将有所不同。Java序列化过程依赖于正确的序列化对象恢复状态的,并在序列化对象序列版本不匹配的情况下引发java.io.InvalidClassException无效类异常。
序列化时,你希望某些成员不要序列化?你如何实现它?
答:有时候也会变着形式问,比如问什么是瞬态trasient变量,瞬态和静态变量会不会得到序列化等,所以,如果你不希望任何字段是对象的状态的一部分,然后声明它静态或瞬态根据你的需要,这样就不会是Java序列化过程中被包含在内
如果一个类中的一个成员为实现可序列化接口,会发生什么情况?
答:如果尝试序列化实现可序列化的类的对象,但该对象包含对不可序列化类的引用,则在运行时将引发不可序列化异常NotSerializableException
如果类是可序列化的,但其超类不是,则反序列化后从超级类继承的实例变量的状态如何?
答:Java序列化过程仅在对象层次都是可序列化结构中继续,即实现Java中可序列化接口,并且从超级类继承的实例变量的值将通过调用构造函数初始化,在反序列化过程中不可序列化的超级类
是否可以自定义序列化过程,或者是否可以覆盖Java中的默认序列化过程?
假设新类的超级类实现可序列化接口,如何避免新类被序列化?
答:对于序列化一个对象需调用ObjectOutputStream.writeObject(saveThisObject),并用ObjectInputStream.readObject()读取对象,但Java虚拟机为你提供的还有一件事,是定义这个两个方法。如果在类中定义这两个方法,则JVM将调用这两个方法,而不是应用默认序列化机制。你可以在此处通过执行任何类型的预处理或后处理任何来自定义对象序列化和反序列化的行为。
在Java中的序列化和反序列化过程中使用哪些方法?
答:考察你是否熟悉readObject()的用法、writeObject()、readExternal()和writeExternal()。Java序列化由java.io.ObjectOutputStream类完成。该类是一个筛选器流,它封装在较低级别的字节流中,以处理序列化机制。要通过序列化机制存储任何对象,我们调用ObjectOutputStream.writeObject(savethisobject),并反序列化该对象,我们称之为ObjectInputStream.readObject()方法。调用以writeObject()方法在java中触发序列化过程。关于readObject()方法,需要注意的一点很重要一点是,它用于从持久性读取字节,并从这些字节创建对象,并返回一个对象,该对象需要类型强制转换为正确的类型。