Java 序列化

Serializable 接口、对象序列化与反序列化、serialVersionUID 与 transient。

Intermediate
Key Points实现 Serializable 即可序列化;transient 字段不参与;务必显式声明 serialVersionUID 避免版本不兼容。

Serializable 接口

Serializable is a marker interface with no methods: implementing it tells the JVM the class may be serialised. Subclasses inherit that automatically.

Java
import java.io.Serializable;

class Employee implements Serializable {
    private static final long serialVersionUID = 1L;

    String name;
    int age;
    transient String password;

    Employee(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }
}

public class MarkerDemo {
    public static void main(String[] args) {
        Employee e = new Employee("Tom", 20, "secret");

        System.out.println(e instanceof Serializable);
        System.out.println(e.name + " " + e.password);
    }
}
Output
true
Tom secret

序列化对象

ObjectOutputStream.writeObject writes an object to a byte stream — a file or a socket. Only the non-transient fields of a serialisable object are written.

Java
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Point implements Serializable {
    private static final long serialVersionUID = 1L;

    int x, y;
    transient int cached;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
        this.cached = 999;
    }
}

public class SerializeDemo {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(bos)) {
            out.writeObject(new Point(1, 2));
        }

        System.out.println(bos.size() > 0);
    }
}
Output
true

反序列化对象

ObjectInputStream.readObject restores it. Deserialisation skips constructors and restores fields straight from the stream, so transient fields come back as defaults (0 here).

Java
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Point implements Serializable {
    private static final long serialVersionUID = 1L;

    int x, y;
    transient int cached;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
        this.cached = 999;
    }
}

public class DeserializeDemo {
    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(bos)) {
            out.writeObject(new Point(1, 2));
        }

        try (ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()))) {
            Point p = (Point) in.readObject();
            System.out.println(p.x + "," + p.y);
            System.out.println(p.cached);
        }
    }
}
Output
1,2
0
Without an explicit serialVersionUID the JVM derives one from the class shape; adding a field changes it and old data fails with InvalidClassException. Pin it explicitly.
Native serialisation suits Java-to-Java only. For cross-language, long-lived or externally exposed data use JSON or Protobuf — the native format is tied to class shape and unsafe on untrusted input.

Friends & Partners