How is serialVersionUID serialized in Java?

2019-07-19 14:30发布

问题:

Class members (static) cannot be serialized. The reason is obvious - they are not held by the object(s) of the class. Since they are associated with the class (rather than the object of that class), they are stored separately from the object.

serialVersionUID is declared as a static field within a class that implements the java.io.Serializable interface something like the following.

private static final long serialVersionUID = 1L;

It is used as a version control in a Serializable class. If it is not explicitly declared, will be done automatically by JVM, based on various aspects of the Serializable class, as described by the Java(TM) Object Serialization Specification.

If it is not explicitly declared within the class implementing the Serializable interface then a warning may issue.

The serializable class SomeClass does not declare a static final serialVersionUID field of type long

Is it serialized even though it is static, how or is it an exception to serialization?

回答1:

Serialization is done "magically," with lots of reflection, and has all sorts of special behavior -- including e.g. looking up the static serialVersionUID of the class.



回答2:

Let me clear you the use of serialVersionUID while writing and reading objects to/from file.

In below code, I have written two functions writeObject() and readObj()

writeObject() is for writing the object in file

readObj() is for reading the Object from file

package com.msq;

import java.io.Serializable;

public class A implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    int a;
    transient int b;

    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
    public int getB() {
        return b;
    }
    public void setB(int b) {
        this.b = b;
    }
}
package com.msq;

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;

public class B implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 123L ;
    /**
     * 
     */
    String name;
    A a;

    public B() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

    public static void main(String[] args) {

        //writeObject();
        readObj();
    }

    static void writeObject() {
        B b = new B();
        b.setName("Musaddique");
        A a2 = new A();
        a2.setA(5);
        a2.setB(10);
        b.setA(a2);
        ObjectOutputStream write = null;

        try {
            write = new ObjectOutputStream(new FileOutputStream(
                    "D:\\serObj.bat"));
            write.writeObject(b);
            write.flush();
            write.close();

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    static void readObj() {
        ObjectInputStream reader = null;

        try {
            reader = new ObjectInputStream(
                    new FileInputStream("D:\\serObj.bat"));
            B b1 = (B) reader.readObject();
            System.out.println("name: "+b1.getName());
            System.out.println("value of a: "+b1.getA().getA());
            System.out.println("value of b: "+b1.getA().getB());
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Here I have used serialVersionUID = 123L for class B and serialVersionUID = 1L for class A and also used transient keyword for variable b in order to restrict to save the value of b into file.

1) Write data to file then read the file you will get following output

name: Musaddique
value of a: 5
value of b: 0

you wil get value of b: 0 because we have used transient for b.

Now for testing try to write object by the same call but while reading change the serialVersionUID = 765L then u will get below exception

java.io.InvalidClassException: com.msq.B; local class incompatible: stream classdesc serialVersionUID = 123, local class serialVersionUID = 765
    at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at com.msq.B.readObj(B.java:81)
    at com.msq.B.main(B.java:46)

So, it is necessary to use same serialVersionUID while reading and writing the object from file.

Also, it is used in RMI calls when you in-corporate classes from one machine to another machine or system.



回答3:

The serialVersionUID itself is not serialized. At least, not in the same way as the other properties of your object. Instead it is written out to your output destination as part of a special 'header' that contains information required to rebuild the objects being written.



回答4:

Think of serialVersionUID not as part of the object data being serialized but as part of the class description. The same way that the class name is part of the serialization stream. Full details of the stream format are documented at Grammar for the Stream Format.