IPC-序列化

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


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

  • 不指定serialVersionUID
    系统会在序列化时自动根据class类计算serialVersionUID,如果类有任何变化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)
  • IDE自动生成serialVersionUID
    类如何发生变化,则该ID也会发生变化,反序列化也会报错
  • 手动指明
    如果一些成员发生变化,系统会尽最大程度的恢复数据,但如果系统的发生重大变化(类名,类结构发生变化,此时发序列话也可能失败)。

注意

  • 父类实现Serializable接口,子类被序列化,父类也会被序列化
  • 父类没有实现Serializable接口,子类被序列化,父类不会被序列化

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都是实现序列化并且都可以用于Intent间传递数据
  • Serializable是Java的实现方式,会频繁的IO操作,所以消耗比较大,但是实现方式简单。适用本地存储和网络传输。
  • Parcelable是Android提供的方式,其是将一个对象进行效率比较高,但是实现起来复杂一些 。

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容

  • 段子 公园里,一位仙风鹤骨的老者在打太极,一招一式都仙气十足,一个年轻人走过去:“大爷,太极这玩意儿花拳绣腿,你练...
    大公爵阅读 17,817评论 4 41
  • JAVA序列化机制的深入研究 对象序列化的最主要的用处就是在传递,和保存对象(object)的时候,保证对象的完整...
    时待吾阅读 10,868评论 0 24
  • Android数据序列化总结 目录介绍 1.序列化简单介绍1.1 序列化的概念1.2 序列化是做什么用的1.3 序...
    杨充211阅读 1,075评论 0 5
  • 2.1 Activity 2.1.1 Activity的生命周期全面分析 典型情况下的生命周期:在用户参与的情况下...
    AndroidMaster阅读 3,044评论 0 8
  • 这里强烈建议把前面两篇文章看一遍,因为前面两篇文章对后面大家对android的IPC的理解帮助很大,本片文章主要内...
    Sophia_dd35阅读 908评论 0 4