读书笔记:浅谈Java的序列化

之前看过一遍《Java编程思想》,把书中的代码理解了一遍,也都敲过一遍。但是很多比较深入的知识在实际的工作中并未使用到,因此都忘记了,为了给自己做一些巩固,在以后的时间里,我会努力地做一些关于这些内容的读书笔记,以加强自己的理解
Java的序列化是指将Java对象转化为可在磁盘或者其它存储介质中保存的字节序列,以便在后续的操作中将这个字节序列重新复原为Java对象,存储的字节序列可以写入文件亦可以通过网络进行传输。那么什么对象可以被序列化呢?被序列化的对象必须实现Serializable接口,请看下例:

package com.fan;

import java.io.*;
import java.util.Random;

/**
 * Created by Alpha on 17/4/16.
 */
class Data implements Serializable {
    private int n;
    public Data(int n){this.n = n;}
    public String toString(){return Integer.toString(n);}
}

public class Worm implements Serializable{
    private static Random rand = new Random(47);
    private Data d[] = {
            new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10)),
            new Data(rand.nextInt(10))
    };

    private Worm next;
    private char c;

    public Worm(int i,char x){
        System.out.println("Worm constructor:" + i);
        c = x;
        if(--i > 0){
            next = new Worm(i,(char)(x + 1));
        }
    }

    public Worm(){
        System.out.println("Default constructor");
    }
    public String toString(){
        StringBuilder result = new StringBuilder(":");
        result.append(c);
        result.append("(");
        for(Data dat : d)
            result.append(dat);
        result.append(")");
        if(next != null)
            result.append(next);
        return result.toString();
    }

    public static void test() throws IOException, ClassNotFoundException {
        Worm w = new Worm(6,'a');
        System.out.println("w = " + w);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
        out.writeObject("Worm storage");
        out.writeObject(w);
        out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
        String s = (String) in.readObject();
        Worm w2 = (Worm) in.readObject();
        System.out.println(s + "w2 = " + w2);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("worm storage");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
        s = (String) in2.readObject();
        Worm w3 = (Worm) in2.readObject();
        System.out.println(s + "w3 = " + w3);
    }
}

输出如下:

在上面的例子中我们可以看到,我们定义了两个类,DataWorm,它们都实现了Serializable接口,在测试方法中我们创建一个包含6个Worm类对象并将这些对象写到了文件worm.out中,看上面的读取步骤,与写入的步骤相同,我们也是先读取一个字符串对象再读取一个Worm对象

如上例,假如我们将写的对象的序列化文件通过网络传输给其它的计算机,那么其它的计算机是不是同样也能解析出这个对象呢,答案是不一定,假如另一台计算机中的classpath中没有上述的Data类和Worm类,那么就会抛出一个ClassNotFoundException的异常

Externalizable

假如我们需要序列化一个对象,但是又不希望将这个对象的所有成员都序列化,比如登录表单,我们只希望提供给用户用户名而不是密码,那么我们可以将包含用户名密码的类通过实现Externalizable接口来实现,请看下面的实例

package com.fan;

import java.io.*;

/**
 * Created by Alpha on 17/4/16.
 */
public class Blips3 implements Externalizable {
    private int i;
    private String s;
    public  Blips3(){
        System.out.println("Blips3 constructor");
    }

    public Blips3(String x,int a){
        s = x;
        i = a;
    }
    public String toString(){return s + i;}
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("Blips3.writeExternal");
        out.writeObject(s);
        out.writeInt(i);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        System.out.println("Blips3.readExternal");
        s = (String) in.readObject();
        i = in.readInt();
    }

    public static void test() throws IOException, ClassNotFoundException {
        System.out.println("Constructing objects:");
        Blips3 b3 = new Blips3("A String " , 47);
        System.out.println(b3);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Blip3.out"));
        System.out.println("Saving object:");
        out.writeObject(b3);
        out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("Blip3.out"));
        System.out.println("Recovering b3:");
        b3 = (Blips3) in.readObject();
        System.out.println(b3);
    }
}

输出如下


如上,我们在使用Externalizable接口来进行对象的初始化时,我们必须实现Externalizable类的两个接口writeExternalreadExternal,这个过程和Serializable接口的不太一样,Serializable是以二进制为基础来对对象进行存储,而Externalizable则需要调用构造器,写入时调用writeExternal,读取时调用readExternal,因此我们假如我们不想某个成员的内容被序列化,我们可以不在writeExternal方法里将其写入输出文件。注意在使用序列化写入或读取时,写入的方法和读取的对应的方法要一致

transient关键字

利用Serializable也可以实现对象的部分成员序列化,那就是对不需要序列化的成员使用transient关键字,如下例所示

package com.fan;

import java.io.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by fanwenlong on 17/4/16.
 */
public class Logon implements Serializable {
    private Date date = new Date();
    private String username;
    private transient String password;
    public Logon(String username,String password){
        this.username = username;
        this.password = password;
    }
    public String toString(){
        return "logon info:\n username:" + username + "\n date:" + date + "\n password:" + password;
    }
    public static void test() throws IOException, InterruptedException, ClassNotFoundException {
        Logon logon = new Logon("Aplha","hello");
        System.out.println("Logon logon = " + logon);
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
        o.writeObject(logon);
        o.close();
        TimeUnit.SECONDS.sleep(1);
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
        System.out.println("Recoving object at:" + new Date());
        logon = (Logon) in.readObject();
        System.out.println("logon logon = " + logon);
    }
}

结果如下


可以看到,上面的password写入序列化后再次的值为空,说明其没有被写入保存

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

推荐阅读更多精彩内容

  • JAVA序列化机制的深入研究 对象序列化的最主要的用处就是在传递,和保存对象(object)的时候,保证对象的完整...
    时待吾阅读 10,842评论 0 24
  • 一、 序列化和反序列化概念 Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化de...
    步积阅读 1,439评论 0 10
  • 官方文档理解 要使类的成员变量可以序列化和反序列化,必须实现Serializable接口。任何可序列化类的子类都是...
    狮_子歌歌阅读 2,396评论 1 3
  • 有人的地方就有江湖,有江湖的地方就有矛盾!任何组织里难能幸勉,党派、团体、社群、协会、家庭……但任何矛盾最终升级成...
    黄健歌阅读 613评论 3 2
  • 王梓亦用身体堵着门,她因为激动,身体剧烈的颤抖着。她的脚下是打碎的盘子、散落的衣服,好像整个屋子里的东西全部跑出来...
    许一帆阅读 358评论 10 1