Java序列化存储对象时FileOutputStream所在try块直接跳转catch块问题
问题核心原因
filename字段定义和访问错误
如果你调用save方法的Player对象是从历史存档反序列化得到的,被transient修饰的filename字段不会参与序列化,反序列化后该字段值为null,传入FileOutputStream构造函数时会直接抛出NullPointerException进入catch块。
如果save方法定义在Player类外部,filename是Player的私有实例字段,外部类无法直接访问,也会触发运行时异常。
同时filename是固定的存档文件名,完全不需要定义为实例成员,更不需要加transient修饰。- 异常信息被屏蔽
当前catch块只打印了自定义提示,没有输出具体异常栈,无法第一时间定位错误原因。 - 流资源未安全释放
当前手动关闭流的写法如果在writeObject阶段抛出异常,流不会正常关闭,可能导致文件句柄泄漏。
修复方案
- 调整
Player类中filename的定义,改为静态常量:
final class Player implements Serializable{ private static final long serialVersionUID = 2676858593456923114L; // 改为静态常量,不需要序列化也全局有效 public static final String FILENAME = "BSR.data"; // 其余原有字段保持不变 private int hp; @SuppressWarnings("rawtypes") private ArrayList<ArrayList> inventory = new ArrayList<>(); private ArrayList<String> myLevelUps = new ArrayList<>(); private ArrayList<Crystal> myCrystals = new ArrayList<>(); private ArrayList<Weapon> myWeapons = new ArrayList<>(); private int myLevel = 0; private int myGold; }
- 重构
save方法,使用try-with-resources自动管理流资源,添加异常栈打印:
void save(Player player) { try (FileOutputStream out = new FileOutputStream(Player.FILENAME); ObjectOutputStream objectOut = new ObjectOutputStream(out)) { objectOut.writeObject(player); System.out.println("你的游戏已存档到" + Player.FILENAME); } catch (Exception e) { System.err.println("无法创建游戏存档数据"); // 打印异常栈定位具体问题 e.printStackTrace(); } }
额外注意项
请确认inventory字段中存储的嵌套ArrayList的元素类型实现了Serializable接口,泛型擦除后如果元素不可序列化,写入对象时也会抛出NotSerializableException。
内容的提问来源于stack exchange,提问作者Bryan Petko
相关产品推荐
相关产品推荐

