Java序列化读写.ser文件时HashMap出现重复管理员条目问题排查
问题根因
- Credentials类toString方法实现不符合预期:你生成HashMap存储键时使用的是
Encryption.SHA_512(credentials.toString()),如果Credentials类没有重写toString方法,会默认调用Object类的原生实现,输出格式为类名@内存地址哈希值。每次应用运行时新创建的Credentials对象内存地址不同,toString输出结果就不同,对应的SHA512哈希值每次都不一样。这就导致插入前的键存在性校验永远不命中,每次都会生成新的键插入管理员数据,看起来就是重复的管理员条目。 - selectUser方法逻辑和插入逻辑不匹配:initAdmin的插入判断用的是
selectUser(admin.getCredentials())==null,而你的HashMap键是Credentials的哈希字符串,如果selectUser方法没有先把传入的Credentials参数转成对应的SHA512哈希再查询,而是直接用Credentials对象作为键查询String类型键的HashMap,永远会返回null,也会导致每次都走插入逻辑。 - (次要优化点)read方法存在冗余异常:空文件时直接创建ObjectInputStream读取会固定抛出EOFException,属于可提前规避的异常。
修复方案
- 重写Credentials类的toString方法,保证相同账号密码的Credentials对象输出的字符串完全一致,也可以单独写
getKey()方法返回拼接的账号密码作为哈希源,避免后续toString逻辑被修改影响存储:
// Credentials类新增代码 @Override public String toString() { return "Credentials{username='" + username + "', password='" + password + "'}"; }
- 修正selectUser方法逻辑,和insert逻辑对齐,先转哈希再查询:
public User selectUser(Credentials credentials) throws NoSuchAlgorithmException { if (credentials == null) return null; String hash = Encryption.SHA_512(credentials.toString()); return users.get(hash); }
- (可选优化)修改read方法,提前判断空文件避免不必要的异常抛出:
public Object read() { Object obj = null; File temp = new File(this.filename); try { // 空文件直接返回null,不用读取 if (!temp.exists() || temp.length() == 0) { temp.createNewFile(); return null; } try (FileInputStream fileIn = new FileInputStream(temp); ObjectInputStream objectIn = new ObjectInputStream(fileIn)) { obj = objectIn.readObject(); } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return obj; }
内容的提问来源于stack exchange,提问作者laegil
相关产品推荐
相关产品推荐

