Android-序列化/反序列化

2020-08-27  本文已影响0人  有腹肌的豌豆Z

什么是序列化/反序列化?

什么时候使用序列化

序列化是干啥用的?

怎么序列化

对象如何序列化?

1、Student类定义
public class Student implements Serializable {

    private String name;
    private Integer age;
    private Integer score;
    
    @Override
    public String toString() {
        return "Student:" + '\n' +
        "name = " + this.name + '\n' +
        "age = " + this.age + '\n' +
        "score = " + this.score + '\n'
        ;
    }
    // ... 其他省略 ... 这里省略了set()、get()方法 
}
2、序列化
public static void serialize(  ) throws IOException {

    Student student = new Student();
    student.setName("CodeSheep");
    student.setAge( 18 );
    student.setScore( 1000 );

    ObjectOutputStream objectOutputStream = 
        new ObjectOutputStream( new FileOutputStream( new File(context.getCacheDir()+"/student.txt") ) );
    objectOutputStream.writeObject( student );
    objectOutputStream.close();
    
    System.out.println("序列化成功!已经生成student.txt文件");
    System.out.println("==============================================");
}
3、反序列化
public static void deserialize(  ) throws IOException, ClassNotFoundException {
    ObjectInputStream objectInputStream = 
        new ObjectInputStream( new FileInputStream( new File(context.getCacheDir()+"/student.txt") ) );
    Student student = (Student) objectInputStream.readObject();
    objectInputStream.close();
    
    System.out.println("反序列化结果为:");
    System.out.println( student );
}
4、运行结果
序列化成功!已经生成student.txt文件
==============================================
反序列化结果为:
Student:
name = CodeSheep
age = 18
score = 1000

Serializable接口

public interface Serializable {
}
试想,如果上面在定义Student类时忘了加implements Serializable时会发生什么呢?
serialVersionUID号有何用?
private static final long serialVersionUID = -4392658638228508589L;
从这地方最起码可以得出两个重要信息:

Parcelable

AndroidStudio中的快捷生成方式

Parcel的简介 [ˈpɑːrsl]

Parcel模型

Parcelable中的三大过程介绍(序列化,反序列化,描述)

/**
 * ================================================
 * 作    者:SharkZ
 * 邮    箱:229153959@qq.com
 * 创建日期:2020/8/26  22:51
 * 描    述
 * 修订历史:
 * ================================================
 */
public class MyParcelable implements Parcelable {

    private String paramsA;
    private int paramsB;
    private boolean paramsC;

    public MyParcelable() {

    }

    public MyParcelable(String paramsA, int paramsB, boolean paramsC) {
        this.paramsA = paramsA;
        this.paramsB = paramsB;
        this.paramsC = paramsC;
    }

    public String getParamsA() {
        return paramsA;
    }

    public void setParamsA(String paramsA) {
        this.paramsA = paramsA;
    }

    public int getParamsB() {
        return paramsB;
    }

    public void setParamsB(int paramsB) {
        this.paramsB = paramsB;
    }

    public boolean isParamsC() {
        return paramsC;
    }

    public void setParamsC(boolean paramsC) {
        this.paramsC = paramsC;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.paramsA);
        dest.writeInt(this.paramsB);
        dest.writeByte(this.paramsC ? (byte) 1 : (byte) 0);
    }

    protected MyParcelable(Parcel in) {
        this.paramsA = in.readString();
        this.paramsB = in.readInt();
        this.paramsC = in.readByte() != 0;
    }

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

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

两种特殊情况

1、凡是被static修饰的字段是不会被序列化的

对于第一点,因为序列化保存的是对象的状态而非类的状态,所以会忽略static静态域也是理所应当的。

2、凡是被transient修饰符修饰的字段也是不会被序列化的

Parcelable 与 Serializable 区别

(1)两者的实现差异

(2)两者的设计初衷

(3)两者效率选择

序列化的受控和加强

约束性加持

那怎么个受控法呢?

private void readObject( ObjectInputStream objectInputStream ) throws IOException, ClassNotFoundException {

    // 调用默认的反序列化函数
    objectInputStream.defaultReadObject();

    // 手工检查反序列化后学生成绩的有效性,若发现有问题,即终止操作!
    if( 0 > score || 100 < score ) {
        throw new IllegalArgumentException("学生分数只能在0到100之间!");
    }
}

单例模式增强

public class Singleton implements Serializable {

    private static final long serialVersionUID = -1576643344804979563L;

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton singleton = new Singleton();
    }

    public static synchronized Singleton getSingleton() {
        return SingletonHolder.singleton;
    }
}

public class Test2 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        ObjectOutputStream objectOutputStream =
                new ObjectOutputStream(
                    new FileOutputStream( new File("singleton.txt") )
                );
        // 将单例对象先序列化到文本文件singleton.txt中
        objectOutputStream.writeObject( Singleton.getSingleton() );
        objectOutputStream.close();

        ObjectInputStream objectInputStream =
                new ObjectInputStream(
                    new FileInputStream( new File("singleton.txt") )
                );
        // 将文本文件singleton.txt中的对象反序列化为singleton1
        Singleton singleton1 = (Singleton) objectInputStream.readObject();
        objectInputStream.close();

        Singleton singleton2 = Singleton.getSingleton();

        // 运行结果竟打印 false !
        System.out.println( singleton1 == singleton2 );
    }

}

解决办法是:在单例类中手写readResolve()函数,直接返回单例对象,来规避之:
private Object readResolve() {
    return SingletonHolder.singleton;
}

App 性能优化

上一篇 下一篇

猜你喜欢

热点阅读