ArrayList序列化与反序列化问题:读取文件返回空集合
解决Java序列化ArrayList后反序列化获取空集合的问题
问题描述
尝试将ArrayList<User>写入文件,读取后输出完整集合时得到空结果,后续计划从中随机选取元素。以下是原代码:
原序列化代码
public void oStream(User user) { ArrayList<User> people = new ArrayList<User>(); people.add(user); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt", true))) { oos.writeObject(people); } catch (IOException ex) { System.out.println(ex.getMessage()); } }
原反序列化代码
public ArrayList<User> iStream() { ArrayList<User> people = new ArrayList<>(); try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) { for (User p : people) people.add(p); people = (ArrayList<User>) ois.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); } return people; }
User类代码
public class User implements Serializable { private String login; private String password; private String email; private String date; public User(String login, String password, String email, String date) { this.login = login; this.password = password; this.email = email; this.date = date; } public User(String login, String password, String email) { this.login = login; this.password = password; this.email = email; } public User() {} // getter和setter方法省略 }
错误原因分析
- 序列化使用追加模式:
ObjectOutputStream初始化时会写入序列化头部信息,用追加模式(FileOutputStream第二个参数为true)会导致文件中存在多个头部,反序列化时无法正确解析后续对象,甚至只能读取第一个写入的集合(若多次调用oStream)。 - 反序列化中的无效循环:
for (User p : people) people.add(p);这段代码遍历的是初始为空的people集合,完全不会执行,属于冗余代码。 - 未处理文件初始化场景:第一次写入时文件不存在,读取会抛出异常,但原代码直接抛出运行时异常,导致无法正常创建初始集合。
- User类无toString方法:即使读取成功,输出集合时会打印对象哈希码,无法直观看到内容,容易误以为是空集合。
修正后的代码
修正后的序列化方法(支持添加新用户到现有集合)
public void oStream(User user) { ArrayList<User> people = new ArrayList<>(); // 先读取文件中已有的集合 try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) { people = (ArrayList<User>) ois.readObject(); } catch (IOException | ClassNotFoundException e) { // 文件不存在或读取失败,说明是第一次写入,保持集合为空 } // 添加新用户 people.add(user); // 覆盖写入文件(避免多个序列化头部) try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"))) { oos.writeObject(people); } catch (IOException ex) { System.out.println(ex.getMessage()); } }
修正后的反序列化方法
public ArrayList<User> iStream() { ArrayList<User> people = new ArrayList<>(); try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) { people = (ArrayList<User>) ois.readObject(); } catch (EOFException e) { // 文件为空,返回空集合 } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); } return people; }
给User类添加toString方法(方便查看集合内容)
在User类中添加:
@Override public String toString() { return "User{" + "login='" + login + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", date='" + date + '\'' + '}'; }
使用说明
- 调用
oStream(User)添加用户时,会先读取文件中已有的集合,添加新用户后覆盖写入,确保文件中只有一个完整的集合。 - 调用
iStream()会返回文件中存储的完整ArrayList<User>,可以直接输出或从中随机选取元素。
内容的提问来源于stack exchange,提问作者AlexSmith
相关产品推荐
相关产品推荐

