面试系列(二)Android中的序列化

文章目录

序列化

为什么要序列化

在进行 Android 开发的时候,无法将对象的引用传递给 Activity 或者 Fragment,我们需要将这些对象放到一个 Intent 或者 Bundle 里面,然后进行传递。但是 Intent 或者是 Bundle 中只能存放进行过序列化后的对象。

什么是序列化

序列化,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。

反序列化

反序列化就是序列化的逆过程,将网络上传输的字节流、本地存储的文件中的内容读取转换为一个对象的过程。

怎么实现序列化

Android 中 Intent 如果要传递类对象,可以通过两种方式。

  • 方式一:Serializable,要传递的类实现 Serializable 接口
  • 方式二:Parcelable,要传递的类实现 Parcelable 接口

Serializable(Java 自带的)

Serializable 是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。 Serializable 接口是一种标识接口,也就是无需实现方法,Java 便会对这个对象进行序列化操作。

serialVersionUID 的作用

  • 类的 serialVersionUID 的默认值完全依赖于 Java 编译器的实现,对于同一个类,用不同的 Java 编译器编译,也有可能会导致不同的serialVersionUID。所以 IDE 才会提示声明 serialVersionUID 的值。
  • 不定义 serialVersionUID 时,Java 会根据类的细节自动生成 serialVersionUID 的值,如果对类的源码做了修改,再重新编译,生成的类的 serialVersionUID 的取值可能会变化,再次反序列化时,若 serialVersionUID 不相等会 crash。
  • 不修改 serialVersionUID,但是 bean 的属性发生改变,则反序列化时此属性会为空,读不到值(取兼容老版本的作用)
  • 只要反序列化时 serialVersionUID 不相等,就会 InvalidClassException Crash

Parcelable(Android 专用)

除了 Serializable 之外,使用 Parcelable 也可以实现相同的效果,
不过不同于将对象进行序列化,Parcelable 方式的实现原理是将一个完整的对象进行分解, 而分解后的每一部分都是 Intent 所支持的数据类型,这样也就实现传递对象的功能了。

两者的区别

两者最大的区别在于存储媒介的不同Serializable 使用 I/O 读写存储在硬盘上。而 Parcelable 是直接 在内存中读写。很明显,内存的读写速度通常大于 IO 读写,所以在 Android 中传递数据优先选择 Parcelable。

Serializable 会使用反射,序列化和反序列化过程需要大量 I/O 操作,序列化过程中会创建很多临时对象,容易触发垃圾回收;Parcelable 自已实现封送和解封(marshalled &unmarshalled)操作,不需要用反射,数据也存放在内存中,效率要快很多。

继承一个实现了 Parcelable 接口的类需要注意的地方

B 类实现了 Parcelable 接口,A 继承自 B,则 A 不需要再实现 Parcelable 接口,但是 A 需要实现相应的抽象方法:describeContents、writeToParcel 还有 CREATOR 构造器等等。还要在 writeToParcel 和相应的构造函数中调用 super 方法。如下,CourseEvent 实现了 Parcelable 接口。

CourseEvent 类:

public class CourseEvent extends ResponseEvent implements Parcelable {
    protected List<CourseInfoDto> cList;      //课程列表
    protected long currentTime;               //socket发送时间戳

    public CourseEvent() {
    }

    protected CourseEvent(Parcel in) {
        cList = in.createTypedArrayList(CourseInfoDto.CREATOR);
        currentTime = in.readLong();
    }

    public static final Creator<CourseEvent> CREATOR = new Creator<CourseEvent>() {
        @Override
        public CourseEvent createFromParcel(Parcel in) {
        return new CourseEvent(in);
        }

        @Override
        public CourseEvent[] newArray(int size) {
        return new CourseEvent[size];
        }
    };

    @Override
    public String toString() {
        return "CourseEvent{" +
            " cList=" + cList +
            ", currentTime=" + currentTime +
            '}';
    }

    public List<CourseInfoDto> getcList() {
        return cList;
    }

    public void setcList(List<CourseInfoDto> cList) {
        this.cList = cList;
    }

    public long getCurrentTime() {
        return currentTime;
    }

    public void setCurrentTime(long currentTime) {
        this.currentTime = currentTime;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeTypedList(cList);
        dest.writeLong(currentTime);
    }
}

WgtCourseInfo 类:

public class WgtCourseInfo extends CourseEvent {

    private int cState;  //0:没上过任何课;1:上课中;2:下课啦

    public WgtCourseInfo() {
        super();
    }

    protected WgtCourseInfo(Parcel in) {
        super(in);
        cState = in.readInt();
    }

    public static final Creator<WgtCourseInfo> CREATOR = new Creator<WgtCourseInfo>() {
        @Override
        public WgtCourseInfo createFromParcel(Parcel in) {
            return new WgtCourseInfo(in);
        }

        @Override
        public WgtCourseInfo[] newArray(int size) {
            return new WgtCourseInfo[size];
        }
    };

    @Override
    public String toString() {
        return "WgtCourseInfo{" +
            "cState=" + cState +
            ", cList=" + cList +
            ", currentTime=" + currentTime +
            '}';
    }

    public int getcState() {
        return cState;
    }

    public void setcState(int cState) {
        this.cState = cState;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);
        dest.writeInt(cState);
    }
}

要记住一点,在 writeToParcel 中write 数据的顺序,要与在构造器中 read 的顺序相同

参考网站

序列化Serializable和Parcelable的理解和区别

Java serialVersionUID 的作用?

Parcelable接口的使用

Serializable 和 Parcelable 的区别

Extending a class that implements Parcelable

How to extend android class which implements Parcelable interface?

Is using Serializable in Android bad?

Android - Problem with the Serializable interface

Parcelable接口的使用

上一篇:字节跳动正式启动2021届秋季校招!分享PDF高清版


下一篇:Android开发还不会这些?靠着这份面试题跟答案,大厂内部资料