必须重写equals和hashCode,否则HashMap购物车中同名同价商品会被视为不同键导致重复添加;应仅基于name、price等不可变业务字段实现,避免含id或stock等可变字段。

商品实体类要不要重写 equals 和 hashCode
必须重写,否则用 HashMap 当购物车时,同名同价不同实例的商品会被当成不同商品,导致重复添加、数量无法累加。
常见错误现象:cart.put(new Product("iPhone", 5999), 1); cart.put(new Product("iPhone", 5999), 2); 后 map size 是 2,不是 1 —— 因为默认 Object.equals 比的是引用。
- 只根据业务上“算同一个商品”的字段重写,比如
name+price(不建议含id,控制台版通常没持久化 ID) - 避免把可变字段(如
stock、discount)放进equals判断,否则对象修改后可能从 map 中“消失” - 用 IDE 自动生成(如 IntelliJ 的
Alt+Insert → equals and hashCode),别手写漏字段
用 Map<Product, Integer> 还是 Map<String, Integer> 做购物车
推荐前者,前提是 Product 已正确重写 equals/hashCode;后者虽省事但埋坑多。
使用场景:控制台交互中用户反复添加/删除/查数量,需要按商品维度聚合操作。
立即学习“Java免费学习笔记(深入)”;
-
Map<Product, Integer>支持直接传入Product对象查数量、更新,逻辑直白,不易错 -
Map<String, Integer>得自己拼 key(如name+"|"+price),一旦拼接规则变、或商品名含|,就出错;且无法反查原始Product实例 - 性能无实质差异;但后者在扩展时(比如加规格属性)会立刻崩,前者只需改
equals逻辑
Map 的增删改查怎么写才不翻车
别直接用 put 覆盖,也别手动 get 判空再 put——Java 8+ 提供更安全的原子操作。
常见错误现象:用户连续两次加同一商品,结果数量只变成 1 或抛 NullPointerException。
- 加购:用
cart.merge(product, 1, Integer::sum),自动处理不存在/已存在场景 - 减购:先
if (cart.containsKey(p)) { int newQty = cart.get(p) - 1; if (newQty - 查总数:用
cart.values().stream().mapToInt(Integer::intValue).sum(),别漏掉空 map 边界 - 清空:直接
cart.clear(),别遍历 remove —— 效率低还容易ConcurrentModificationException
订单确认时怎么把购物车转成不可变结构
控制台流程走到“下单”这步,购物车数据要固化,避免后续操作意外修改影响订单一致性。
容易踩的坑:直接把 cart 引用传给订单对象,之后用户继续加购,订单里的商品数量也跟着变。
- 不要用
Collections.unmodifiableMap(cart)—— 它只防 map 结构修改,value(数量)仍可被原对象改 - 正确做法:构造新
Map,key 用new Product(p.getName(), p.getPrice())(确保不共享引用),value 用当前数量值 - 如果后续要支持订单详情展示,建议订单类里存
List<CartItem>(CartItem是个含product和quantity的不可变 record 或 final 类)
最易被忽略的是 Product 字段可变性——哪怕 equals 写对了,如果用户加购后又调 product.setPrice(4999),这个商品在 map 里的位置就找不到了。控制台小项目也得守住这条线:购物车里的 Product 实例,从加入那一刻起就该视为只读。









