java序列化与反序列化

java序列化与反序列化

对象序列化是一种持久化技术,广泛运用于网络传输、RMI等场景中。java对象存在于JVM运行时,然而有时期望即使JVM关闭了也可以保存当前对象以备将来重新使用或者给其他JVM使用,为解决类似问题可以采用持久化技术。java中对象的序列化就是将对象转化为字符序列存放在磁盘或内存中,反序列化则相反。对象要想序列化,要求相应的类实现Serializable接口。注意,序列化保存的只是对象的状态,并不包含方法和静态成员变量。下面是实现序列化的一个小例子:

public class People implements Serializable {

    private static final long serialVersionUID = -2189866613532876533L;

    public String mName;

    public int mAge;

    public static String mSchool = "WUST";

    public People(String name, int age) {
        mName = name;
        mAge = age;
    }

    public static void setSchool(String mSchool) {
        People.mSchool = mSchool;
    }

    @Override
    public String toString() {
        return "People{" +
                "mName='" + mName + '\'' +
                ", mAge=" + mAge +
                '}';
    }

    public static void main(String[] args) {
        People people = new People("ldg", 22);

        File file = new File("D:\\Users\\lidegui371\\Desktop\\People");

        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
            System.out.println(People.mSchool);
            out.writeObject(people);

            People.setSchool("武汉科技大学");

            ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
            People p1 = (People) in.readObject();
            System.out.println(p1);
            System.out.println(People.mSchool);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

输出为:WUST People{mName='ldg', mAge=22} 武汉科技大学

类中的serialVersionUID用来标识反序列的类与序列化的类是否为同一个类,假如没有声明serialVersionUID,系统在序列化和反序列时会调用相应的算法生成这个标识,一旦这个类有一点修改都会导致这个标识不一样,所以在将之前序列化对象反序列化时会因为serialVersionUID不一样而出错。虚拟机是否允许反序列化不仅取决于类路径和功能代码是否一致,还取决于这两个类的序列化 ID 是否一致。如果serialVersionUID一样,即使类有改动也可以成功地反序列化(如果类添加了字段,值为java初始值,比如int=0,String=null;如果字段减少,则不影响没改变的其他字段)。

transient所修饰的字段可以在序列化时不被序列化到文件中,在反序列化时该字段被赋予初始值。如果想让transient修饰的字段也可以进行序列化与反序列化可以在类中定义writeObjectreadObject方法,自己控制序列化,如果类中没有这两个方法,则系统会调用ObjectOutputStream中的defaultWriteObject方法和ObjectInputStream中的defaultReadObject方法。

在序列化的时候,private字段的数据是以明文的形式存放的,这在网络传输中及其不安全,所以可以在类中定义readObjectwriteObject方法实现序列化数据模糊化,比如:

private void writeObject(ObjectOutputStream out) throws IOException {

        // 第一种写法
        System.out.println("未加密前的年龄:" + mAge);
        ObjectOutputStream.PutField field = out.putFields();
        field.put("mAge", mAge >> 1);
        field.put("mName", mName);
        out.writeFields();
        System.out.println("加密完成");

//        // 第二种写法
//        mAge = mAge >> 2;
//        out.defaultWriteObject();
    }

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

        // 第一种写法
        ObjectInputStream.GetField field = in.readFields();
        mName = (String) field.get("mName", "");
        mAge = field.get("mAge", 0);
        System.out.println("读出来的年龄:" + mAge);
        mAge = mAge << 1;
        System.out.println("解密完成");

//        // 第二种写法
//        in.defaultReadObject();
//        mAge = mAge << 2;
    }

由上可知writeObjectreadObject方法可以自定义控制序列化。控制序列化还可以使用writeReplacereadResolve,只不过使用了这两个方法后是将序列化对象或反序列化的对象给替换了。比如有一个People类,它在writeReplace方法中返回了一个PeopleProxy的代理类,那么序列化的对象就变成了PeopleProxy,序列化与反序列化时与PeopleProxy类中相关的方法有关,所以可以利用这个方法旧类序列化为新版本。readResolve则相反,将反序列化的数据序列化为指定的对象,这个方法可以用来保护性恢复单例。这四者的调用顺序为:writeReplace—>writeObject—>readObject—>readResolve。需要注意的是,当这个类调用了writeReplace后,序列化的控制就转到了这个方法返回的那个对象的类中了。

在JAVA中,序列化时除了实现Serializable还可以实现Externalizable接口,它继承于Serializable并声明了两个abstract方法:writeExternalreadExternal,所以它要求手动实现序列化与反序列化,用法和SerializablewriteObjectreadObject一样。Externalizable在效率上比Serializable要高,但如果不需要自定义序列化过程,一般使用Serializable

在android开发中,除了使用Serializable还可以使用Parcelable实现对象序列化。Serializable使用起来开销较大,通过IO流写入到磁盘和传输到网络,android设计的Parcelable是为了在程序内不同组件间和android跨进程而设计的一种序列化方式,它是通过IBinder通信的消息的载体,携带的数据仅存在内存中,由于内存的读写速度比磁盘的要快,所以在内存间的数据传输推荐使用Parcelable,但因其在持久化和网络传输上操作复杂,在这方面推荐使用Serializable

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

推荐阅读更多精彩内容

  • 如来往已绝 愿山林有鸟鸣 秀木也繁荫
    物欲外星男的游泳池阅读 181评论 0 0
  • 第二章:提高阅读速度的关键 阅读高的指标清单 速度快,有节奏,理解好,宽视距,有目的,意群阅,不同速度,评估,词意...
    杜惠钧阅读 128评论 0 0
  • 徐悲鸿的画价值百万,却屡次赠与一人 徐悲鸿的画一直深受人们的喜爱和追捧,在收藏界也是一画难求。但正所谓宝剑赠英雄,...
    瓷之醉阅读 99评论 0 0
  • 中秋节了,小长假吃吃喝喝那是各种走起哇~ 另外,这一过节吧,总得吃点各种应景的佳节“美食”吧?元宵来汤圆、端午来粽...
    硬派健身阅读 778评论 0 1