You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中用ObjectInputStream无法反序列化含嵌套对象的对象的解决方案

解决包含嵌套对象的Java网络对象传输问题

原问题根源

你的People类实现了Serializable,但嵌套的Player类未实现该接口,直接使用ObjectInputStream/ObjectOutputStream序列化时会抛出NotSerializableException,这是反序列化失败的核心原因。如果不想依赖Java原生序列化,以下是几种可靠的替代方案:

方案1:让嵌套类实现Serializable(原生直接修复)

这是最省事的修复方式,不需要改动传输逻辑,只需给Player类添加Serializable接口:

public class Player implements Serializable {
    // 建议显式声明序列化ID,避免类结构变化导致反序列化失败
    private static final long serialVersionUID = 123456789L;
    private String name;
    
    // 构造方法、getter等原有逻辑保留
}

方案2:JSON序列化(通用跨语言方案)

将对象序列化为JSON字符串传输,接收端再反序列化为对象,无需依赖Serializable接口,可读性强且支持跨语言。常用库有Jackson、Gson,以下是Jackson的示例:

  1. 添加Maven依赖:
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>
  1. 修改发送端(ServerMulticast)的序列化逻辑:
// 替换原ObjectOutputStream相关代码
ObjectMapper mapper = new ObjectMapper();
String jsonStr = mapper.writeValueAsString(p1);
byte[] data = jsonStr.getBytes(StandardCharsets.UTF_8);
// 后续DatagramPacket发送逻辑不变
  1. 修改接收端(ClientMulticast)的反序列化逻辑:
// 替换原ObjectInputStream相关代码
String jsonStr = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
ObjectMapper mapper = new ObjectMapper();
People readObject = mapper.readValue(jsonStr, People.class);

方案3:Protobuf序列化(高性能二进制方案)

Protobuf是Google推出的二进制序列化协议,体积小、传输效率高,适合游戏这类对性能敏感的场景。

  1. 定义.proto描述文件:
syntax = "proto3";

message Player {
    string name = 1;
    // 按需添加Player的其他字段
}

message People {
    string ip = 1;
    Player player = 2;
}
  1. 用Protobuf编译器生成Java类,之后修改传输逻辑:
  • 发送端:
// 将自定义People对象转换为Protobuf生成的对象
PeopleProto.People protoPeople = PeopleProto.People.newBuilder()
    .setIp(p1.getIp())
    .setPlayer(PeopleProto.Player.newBuilder().setName(p1.getPlayer().getName()).build())
    .build();
byte[] data = protoPeople.toByteArray();
// 发送DatagramPacket
  • 接收端:
// 解析二进制数据为Protobuf对象,再转换为自定义People对象
PeopleProto.People protoPeople = PeopleProto.People.parseFrom(packet.getData(), 0, packet.getLength());
Player player = new Player(protoPeople.getPlayer().getName());
People readObject = new People(player, protoPeople.getIp());

方案4:手动序列化/反序列化(完全自定义)

自己实现对象与字节数组的转换逻辑,完全控制序列化过程,适合字段简单的对象:

在People类中添加序列化、反序列化方法:

public byte[] toBytes() throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
    // 按顺序写入字段
    dos.writeUTF(ip);
    dos.writeUTF(player.getName());
    dos.close();
    return baos.toByteArray();
}

public static People fromBytes(byte[] data) throws IOException {
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    DataInputStream dis = new DataInputStream(bais);
    // 按写入顺序读取字段
    String ip = dis.readUTF();
    String playerName = dis.readUTF();
    dis.close();
    return new People(new Player(playerName), ip);
}

发送端调用p1.toBytes()获取字节数组,接收端调用People.fromBytes(packet.getData())还原对象即可。


内容的提问来源于stack exchange,提问作者Akashiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:05:33