从.dat文件加载序列化对象失败,求排查解决
问题分析与解决方案:ObjectInputStream读取对象时的重复读取问题
嘿,我看了你的代码,马上就发现了问题的根源——你的load2方法里重复调用了readObject(),这直接导致对象被跳过,Faculty根本没被处理!
核心问题拆解
你看这段判断逻辑:
if(inStream.readObject().toString().startsWith("[Student")) { System.out.println("FOUND A STUDENT---------"); tempStudent = (Student) inStream.readObject(); // ... } if(inStream.readObject().toString().startsWith("[Faculty")) { System.out.println("FOUND A FACULTY---------"); tempFaculty = (Faculty) inStream.readObject(); // ... }
每次调用inStream.readObject()都会从文件流里读取下一个对象。比如:
- 第一次调用
readObject()读取了你的Faculty对象,用来判断是不是Student——显然不是,所以跳过第一个if块 - 接着第二个if块又调用
readObject(),这次读取的是第一个Student对象,判断是不是Faculty——也不是,跳过 - 循环继续,下一次第一个if调用
readObject()读取第二个Student,符合条件,然后又调用一次readObject(),这时候已经到文件末尾了,直接触发EOFException
结果就是:Faculty被读取了但没处理,第一个Student被读取了但没处理,只有第二个Student被尝试加载,但也因为重复读取导致逻辑混乱,最终都没正确存入内存。
对比你的Course加载方法,它就很正确:先读取一次对象到变量,再处理,没有重复读取的问题。
修正后的load2方法
把读取对象的操作放在判断之前,先保存对象引用,再用instanceof判断类型(比依赖toString更可靠):
public void load2() { String fileName = "people_bag2.dat"; FileInputStream inFile; ObjectInputStream inStream = null; Object obj; // 先统一存读取到的对象 try { inFile = new FileInputStream(fileName); inStream = new ObjectInputStream(inFile); while (true) { obj = inStream.readObject(); // 只读取一次,保存引用 if (obj instanceof Student) { System.out.println("FOUND A STUDENT---------"); Student tempStudent = (Student) obj; // 直接使用读取到的对象,不需要重复读取 Student person = new Student(tempStudent.getFirstName(), tempStudent.getLastName(), tempStudent.getPhoneNumber(), tempStudent.getMajor(), tempStudent.getCourseBag()); add(tempStudent); } else if (obj instanceof Faculty) { System.out.println("FOUND A FACULTY---------"); Faculty tempFaculty = (Faculty) obj; Faculty f = new Faculty(tempFaculty.getFirstName(), tempFaculty.getLastName(), tempFaculty.getPhoneNumber(), tempFaculty.getTitle(), tempFaculty.getSalary()); add(f); } } } catch (EOFException e) { // 处理文件结束 try { if(Utilities.DEBUG) { System.out.println("[PeopleBag]: Loaded "+fileName+" into memory successfully."); } if (inStream != null) { inStream.close(); } } catch (IOException ex) { ex.printStackTrace(); } } catch (FileNotFoundException e) { System.out.println("File named "+ fileName +" not found.\n"); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } }
额外注意事项
- 永远不要依赖
toString()的格式来判断对象类型,instanceof是Java中判断对象类型的标准方式,更稳定可靠 - 读取对象流时,每次
readObject()都会移动流的指针,一定要确保每次只读取一次,并用变量保存引用,避免流位置混乱 - 记得在所有异常分支里正确关闭流,或者用try-with-resources语法自动管理资源,减少资源泄漏风险
内容的提问来源于stack exchange,提问作者Corey
相关产品推荐
相关产品推荐

