Reading Notes: Talking about Java Serialization

Posted by mobile target on Tue, 09 Jul 2019 00:26:45 +0200

I've read "Java Programming Thought" once before, understood the code in the book and knocked it once. But a lot of in-depth knowledge is not used in actual work, so I forgot that in order to consolidate myself, in the future, I will try to do some reading notes on these contents to strengthen my understanding.
Java serialization refers to the conversion of Java objects into byte sequences that can be stored on disk or other storage media in order to restore the byte sequences to Java objects in subsequent operations. The stored byte sequences can be written to files and transmitted over the network. So what objects can be serialized? The serialized object must implement the Serializable interface, as shown in the following example:

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);
    }
}

The output is as follows:


In the example above, we can see that we define two classes, Data and Worm, which implement the Serializable interface. In the test method, we create a six Worm class object and write these objects to the file worm.out. Look at the reading steps above, as in the writing steps, we'll do the same. Read a string object and a Worm object

For example, if we transfer the serialized files of the objects we write to other computers over the network, can other computers also parse the objects? The answer is not certain. If there are no Data classes and Worm classes mentioned above in the classpath of another computer, a ClassN will be thrown out. The exception of otFoundException

Externalizable

If we need to serialize an object, but we don't want to serialize all the members of the object, such as the login form. We only want to provide the user name instead of the password, then we can implement the class containing the user name and password by implementing the Externalizable interface. See the example below.

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);
    }
}

The output is as follows



As mentioned above, when we use Externalizable interface to initialize objects, we must implement two interfaces of Externalizable class, writeExternal and readExternal. This process is different from Serializable interface. Serializable is based on binary to store objects, while Externalizable needs to be tuned. With a constructor, we call writeExternal when writing and readExternal when reading, so if we don't want the content of a member to be serialized, we can write it to the output file in the writeExternal method. Note that when serialized writing or reading is used, the method of writing is consistent with the corresponding method of reading.

transient keyword

Serializable can also be used to serialize some members of an object, that is, to use the transient keyword for members that do not need serialization, as shown in the following example

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);
    }
}

give the result as follows



As you can see, the above password is written to serialize and the value is empty again, indicating that it has not been written to save.

Topics: Java network Programming