Java 序列化

目录

什么是 Java 序列化?

如何实现 Java 序列化?

1. 实现 Serializable 接口

2. 序列化对象

3. 反序列化对象

注意事项

完整示例

Employee.java

SerializeDemo.java

DeserializeDemo.java


Java 序列化是一种将 Java 对象转换为字节序列的过程,这一过程主要用于将对象的状态持久保存到磁盘上,或通过网络传输到另一个运行 Java 的环境中。反序列化则是将这种字节序列恢复为 Java 对象。这种机制在多种场景下非常有用,比如在分布式系统中传输对象、保存对象状态以及进行深度复制等。

什么是 Java 序列化?

Java 序列化允许将对象转换成流,以便能够将其保存在数据库、文件或内存中,或者通过网络在不同的 JVM 之间传输。反序列化则是将已序列化的字节流重新构建成原来的对象。

如何实现 Java 序列化?

要实现 Java 序列化,你需要:

  1. 让你的类实现 java.io.Serializable 接口。
  2. 使用 ObjectOutputStream 将对象序列化。
  3. 使用 ObjectInputStream 将字节流反序列化成对象。

1. 实现 Serializable 接口

Serializable 是一个标记接口(没有方法的接口),用于使 Java 虚拟机(JVM)认识该类的对象可以被序列化。

import java.io.Serializable;

public class MyClass implements Serializable {
    private static final long serialVersionUID = 1L;  // 推荐添加这个版本号

    // 类的成员变量和方法
}

2. 序列化对象

使用 ObjectOutputStream 类将对象写入到输出流。以下是一个示例:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializeDemo {
    public static void main(String[] args) {
        MyClass obj = new MyClass();  // MyClass 必须实现 Serializable 接口
        try {
            FileOutputStream fileOut = new FileOutputStream("object.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(obj);
            out.close();
            fileOut.close();
            System.out.println("Serialized data is saved in object.ser");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3. 反序列化对象

使用 ObjectInputStream 类从文件中读取字节流并转换回原始对象。以下是一个示例:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class DeserializeDemo {
    public static void main(String[] args) {
        MyClass obj = null;
        try {
            FileInputStream fileIn = new FileInputStream("object.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            obj = (MyClass) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException i) {
            i.printStackTrace();
        } catch (ClassNotFoundException c) {
            System.out.println("MyClass class not found");
            c.printStackTrace();
        }
        System.out.println("Deserialized MyClass...");
        // 输出 obj 的内容
    }
}

注意事项

  1. 非序列化成员: 使用 transient 关键字标记的成员变量不会被序列化。反序列化后,这些成员变量的值会被设为类型默认值(如 null0false)。

  2. 序列化 ID: 在每个可序列化的类中添加 private static final long serialVersionUID 字段是个好习惯。这个序列版本号可以帮助保证序列化对象的版本与反序列化时类的版本一致。

  3. 静态变量: 静态变量属于类的状态,不属于对象的状态,因此不会被序列化。

完整示例

下面是一个更完整的示例,使用一个简单的 Employee 类来展示序列化与反序列化的过程。

Employee.java
import java.io.Serializable;

public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    
    public String name;
    public String address;
    public transient int SSN;
    public int number;
    
    public void mailCheck() {
        System.out.println("Mailing a check to " + name + " at " + address);
    }
}
SerializeDemo.java
import java.io.*;

public class SerializeDemo {
    public static void main(String[] args) {
        Employee e = new Employee();
        e.name = "Reyan Ali";
        e.address = "Phokka Kuan, Ambehta Peer";
        e.SSN = 11122333;
        e.number = 101;

        try {
            FileOutputStream fileOut = new FileOutputStream("employee.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(e);
            out.close();
            fileOut.close();
            System.out.println("Serialized data is saved in employee.ser");
        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}
DeserializeDemo.java
import java.io.*;

public class DeserializeDemo {
    public static void main(String[] args) {
        Employee e = null;
        try {
            FileInputStream fileIn = new FileInputStream("employee.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            e = (Employee) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException i) {
            i.printStackTrace();
            return;
        } catch (ClassNotFoundException c) {
            System.out.println("Employee class not found");
            c.printStackTrace();
            return;
        }
        System.out.println("Deserialized Employee...");
        System.out.println("Name: " + e.name);
        System.out.println("Address: " + e.address);
        System.out.println("SSN: " + e.SSN);  // 注意此处 SSN 为 0,因为它是 transient
        System.out.println("Number: " + e.number);
    }
}

通过这些步骤和示例,你应该能够理解和实现 Java 对象的序列化与反序列化,以便在不同的环境和程序间共享和存储对象状态。

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
当面试中被问到关于Java序列化的问题时,你可以准备以下问题和答案: 问题1:什么是Java序列化? 答:Java序列化是指将Java对象转换为字节流的过程。通过将对象序列化为字节流,我们可以将其持久化保存在文件中或通过网络传输到其他系统。 问题2:为什么要使用Java序列化? 答:Java序列化提供了一种方便的方式来持久化对象数据以及在网络间传输对象。它可以帮助我们保存对象状态并在需要时还原对象。 问题3:如何实现Java序列化? 答:要使一个Java类可序列化,需要满足以下条件: - 类必须实现java.io.Serializable接口。 - 类的所有非瞬态成员变量(即不包含transient关键字修饰的变量)也必须是可序列化的。 问题4:什么是瞬态变量? 答:瞬态变量是指被transient关键字修饰的成员变量。这些变量不会被序列化和反序列化,它们的值在对象反序列化时被设为默认值。 问题5:如何自定义序列化? 答:可以通过实现自定义的writeObject()和readObject()方法来自定义序列化过程。这些方法允许我们在对象序列化和反序列化的过程中控制数据的读写。 问题6:Java序列化中有什么安全问题? 答:Java序列化存在安全隐患,主要是由于它可以导致远程代码执行。攻击者可以通过构造恶意序列化数据来执行未授权的代码。为了解决这个问题,可以使用一些安全机制,如禁用某些类的序列化或使用安全的序列化方案。 这些问题和答案应该能帮助你在面试中回答关于Java序列化的问题。当然,在回答时确保理解问题的背景和提供具体的例子将有助于展示你的知识和理解能力。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值