读书笔记:浅谈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);
    }
}

输出如下:

读书笔记:浅谈Java的序列化_第1张图片

在上面的例子中我们可以看到,我们定义了两个类,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);
    }
}

输出如下

读书笔记:浅谈Java的序列化_第2张图片

如上,我们在使用 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);
    }
}

结果如下

读书笔记:浅谈Java的序列化_第3张图片

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

你可能感兴趣的:(读书笔记:浅谈Java的序列化)