在Java中,对象的序列化是指将对象转换为字节序列的过程,以便可以将其存储到文件、数据库或通过网络进行传输。反之,对象的反序列化则是将字节序列转换回对象的过程。

Java提供了默认的序列化机制,可以通过实现Serializable接口来实现对象的序列化与反序列化。Serializable接口是一个标记接口,没有定义任何方法,它只是用来标识一个类的对象可以被序列化。当一个类实现了Serializable接口后,就可以将该类的对象转换为字节序列进行存储或传输。

下面我们通过一个简单的示例来演示Java中对象的序列化与反序列化:

import java.io.*;

class Student implements Serializable {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class SerializationDemo {
    public static void main(String[] args) {
        Student student = new Student("张三", 20);

        try {
            FileOutputStream fileOut = new FileOutputStream("student.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(student);
            out.close();
            fileOut.close();
            System.out.println("对象已序列化并保存到student.ser文件中");
        } catch (IOException e) {
            e.printStackTrace();
        }

        Student deserializedStudent = null;

        try {
            FileInputStream fileIn = new FileInputStream("student.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            deserializedStudent = (Student) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (deserializedStudent != null) {
            System.out.println("反序列化结果:");
            System.out.println("姓名:" + deserializedStudent.getName());
            System.out.println("年龄:" + deserializedStudent.getAge());
        }
    }
}

在上面的示例中,我们定义了一个Student类,它实现了Serializable接口。该类有两个属性:name和age,以及相应的getter方法。在main方法中,我们创建了一个Student对象,并将其序列化到student.ser文件中。

接下来,我们尝试将student.ser文件中的字节序列反序列化为一个Student对象。我们通过FileInputStream从文件中读取字节序列,然后通过ObjectInputStream将字节序列转换为Student对象。

最后,我们打印反序列化结果,验证了反序列化是否成功。

除了默认的序列化机制,Java还提供了自定义序列化的方式。在某些情况下,我们可能希望对对象的序列化过程进行一些定制化的处理,例如对敏感数据进行加密、对某些字段进行特殊处理等。

为了实现自定义序列化,我们可以在实现Serializable接口的类中添加以下两个方法:

  • private void writeObject(ObjectOutputStream out) throws IOException:该方法在对象被序列化之前被调用,我们可以在该方法中对需要进行定制化处理的字段进行加密、特殊处理等。
  • private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException:该方法在对象被反序列化之后被调用,我们可以在该方法中对需要进行定制化处理的字段进行解密、特殊处理等。

下面我们通过一个示例来演示自定义序列化的过程:

import java.io.*;

class Person implements Serializable {
    private String name;
    private int age;
    private transient String password;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getPassword() {
        return password;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        // 对password字段进行加密处理
        password = encrypt(password);
        out.defaultWriteObject();
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        // 对password字段进行解密处理
        password = decrypt(password);
    }

    private String encrypt(String password) {
        // 省略加密算法的实现
        return password;
    }

    private String decrypt(String password) {
        // 省略解密算法的实现
        return password;
    }
}

public class CustomSerializationDemo {
    public static void main(String[] args) {
        Person person = new Person("张三", 20, "123456");

        try {
            FileOutputStream fileOut = new FileOutputStream("person.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();
            System.out.println("对象已序列化并保存到person.ser文件中");
        } catch (IOException e) {
            e.printStackTrace();
        }

        Person deserializedPerson = null;

        try {
            FileInputStream fileIn = new FileInputStream("person.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            deserializedPerson = (Person) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (deserializedPerson != null) {
            System.out.println("反序列化结果:");
            System.out.println("姓名:" + deserializedPerson.getName());
            System.out.println("年龄:" + deserializedPerson.getAge());
            System.out.println("密码:" + deserializedPerson.getPassword());
        }
    }
}

在上面的示例中,我们定义了一个Person类,它实现了Serializable接口。该类有三个属性:name、age和password,其中password字段被标记为transient,表示在序列化过程中不进行处理。

在writeObject方法中,我们对password字段进行了加密处理,然后调用out.defaultWriteObject()方法将对象的其他字段进行序列化。

在readObject方法中,我们首先调用in.defaultReadObject()方法将对象的其他字段进行反序列化,然后对password字段进行解密处理。

通过自定义序列化,我们可以对对象的序列化过程进行定制化处理,提高了程序的灵活性和安全性。

总结来说,Java中的对象序列化与自定义序列化是一种将对象转换为字节序列并进行存储或传输的机制。通过实现Serializable接口,我们可以使用默认的序列化机制将对象序列化和反序列化。此外,通过自定义序列化,我们可以对序列化过程进行定制化处理,提高程序的灵活性和安全性。