IPC-序列化

2019-03-08  本文已影响0人  小的橘子

Serializable

序列化实现

package com.nan.mylibrary;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * 要序列化需要实现Serializable接口
 * Created by nan on 18-3-23.
 */

public class Student implements Serializable {
    /**
    *可以不指定,可以由系统生成,也可手动指定,后面具体分析其使用及作用
    */
    private static final long serialVersionUID = -3042243308847924453L;
    public static String TAG;
    int age;
    String name;
    transient String nickname;
    boolean male;

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                ", male=" + male +
                '}' + " | Static TAG:" + TAG;
    }

    Student(int age, String name, String nickname, boolean male) {
        this.age = age;
        this.name = name;
        this.nickname = nickname;
        this.male = male;

    }

    public static void main(String[] args) {
        //1. 第一次运行main中注释的部分,直接输出studnet对象
        /*Student student = new Student(18, "dog", "feifei", false);
        Student.TAG = "hello student";
        System.out.println(student);
        serialize(student);*/
        //2.第二次运行反序列化代码部分,得到反序列化的数据并打印
        Student student1 = (Student) deserialize();
        System.out.println(student1);

    }
    /**
    *序列化对象
    */
    private static void serialize(Object object) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream("cache.txt");
            ObjectOutputStream ouput = new ObjectOutputStream(fileOutputStream);
            ouput.writeObject(object);
            ouput.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("file not found");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IOException");
        }
    }
    /**
    *反序列化对象
    */
    private static Object deserialize() {
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream("cache.txt");
            ObjectInputStream input = new ObjectInputStream(fileInputStream);
            Student student = (Student) input.readObject();
            return student;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  1. 正常打印student对象
Student{age=18, name='dog', nickname='feifei', male=false} | Static TAG:hello student

在当前对象中直接打印student对象可以看到所有信息都正常输出

  1. 反序列打印student对象
Student{age=18, name='dog', nickname='null', male=false} | Static TAG:null

由此可见序列化不会对static变量和transient关键字修饰成员进行序列化

serialVersionUID


反序列得到的对象只是在内容上和序列前对象内容一致,但本质是两个对象

java.io.InvalidClassException: com.nan.mylibrary.Student; local class incompatible: stream classdesc serialVersionUID = 8719351234228157191, local class serialVersionUID = -2675111980170094111
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1829)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1986)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
    at com.nan.mylibrary.Student.deserialize(Student.java:74)
    at com.nan.mylibrary.Student.main(Student.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

注意

Parcelable

实现了Parcelable接口的对象可以实现序列化并可以通过IntentBinder传递

示例

/**
*step1 实现Parcelable接口
*/
public class Student implements Parcelable {

    public static String TAG;
    String name;
    transient String nickname;
    int age;
    boolean male;

    public Student(String name, String nickname, int age, boolean male) {
        this.name = name;
        this.nickname = nickname;
        this.age = age;
        this.male = male;

    }

    /**
     * step5 读取数据必须和序列化中写数据顺序严格一致,否则可能值错乱,也有可能出错
     *
     * @param source
     */
    public Student(Parcel source) {
        this.name = source.readString();
        this.nickname = source.readString();
        this.age = source.readInt();
        this.male = source.readByte() == 1 ? true : false;
        TAG = source.readString();
    }

    /**
     * step2 必须实现,返回0即可
     * TODO:具体作用
     *
     * @return
     */
    @Override
    public int describeContents() {
        return 0;
    }

    //step3 将要序列化的内容写如Parcel
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(nickname);
        dest.writeInt(age);
        dest.writeByte((byte) (male ? 1 : 0));//writeboolean的特殊处理
        dest.writeString(TAG);
    }

    //step4 该CREATOR变量名称不能改变.
    public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel source) {
            //step6 从序列化的对象中创建原始对象
            return new Student(source);
        }

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

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\'' +
                ", male=" + male +
                '}' + " | Static TAG:" + TAG;
    }
}

测试该对象在两个不同进程的Activity传递,通过Intent来传递

MainActivity 进程com.nan.ipc

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View view) {
        Student student = new Student("dog", "feifei", 18, true);
        Student.TAG = "hello student";
        Intent intent = new Intent(this, SecondActivity.class);
        //intent.putExtra接收为基本类型或者Parcelable和Serializable对象
        intent.putExtra("student", student);
        startActivity(intent);
    }
}

SecondActivity 进程com.nan.ipc:second

public class SecondActivity extends Activity {
    public static final String TAG = "SecondActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Student student = getIntent().getParcelableExtra("student");
        Log.i(TAG, "onCreate: " + student);
    }
}

打印log如下

01-01 15:43:14.202 10986 10986 I SecondActivity: onCreate: Student{age=18, name='dog', nickname='feifei', male=true} | Static TAG:hello student

由上可知,写入Parcel中的数据都可以反序列出来,即使是transient修饰符修饰的变量或者static修饰的变量

注意

  1. List和Map也可以序列化,前提是他们里面的每个元素都是可序列化的
  2. 如果序列化时包含已经序列化的对象,在读取是需要传入当前线程的上下文类加载器
book = source.readParcelable(Thread.currentThread().getContentClassLoader());

Serializable和Parcelable的区别

二者的选取规则是:内存序列化上选择Parcelable, 存储到设备或者网络传输上选择Serializable(当然Parcelable也可以但是稍显复杂)

上一篇下一篇

猜你喜欢

热点阅读