优先用 HashMap 存商品,因按编号查询是高频操作,其平均时间复杂度 O(1) 远优于 ArrayList 的 O(n);若需保持插入顺序或导出有序报表,可选 LinkedHashMap 或保留 ArrayList 副本。

用 ArrayList 还是 HashMap 存商品?看查询场景
库存系统最常查的是「根据商品编号找商品」或「遍历所有商品做盘点」。如果频繁按 id 查,HashMap 比 ArrayList 快得多——前者平均 O(1),后者要遍历,最坏 O(n)。但若主要做批量入库、按顺序打印报表,ArrayList 更省内存、遍历更缓存友好。
- 单商品查改多 → 优先用
HashMap,key 设为String id(别用int,避免装箱/溢出) - 需保持插入顺序或导出 Excel 时按录入顺序排列 → 保留
ArrayList副本,或直接用LinkedHashMap - 别把
Product对象塞进TreeMap除非真要按价格/名称排序——它额外开销大,且compareTo写错会导致put失效
Product 类必须重写 equals 和 hashCode 吗?
必须。否则放进 HashSet 或作为 HashMap 的 value 时,哪怕两个对象字段完全一样,contains 也会返回 false;用 remove 删不掉;甚至同一对象 add 两次都成功。
- 只重写
equals不重hashCode→HashMap查不到 - 只重
hashCode不重equals→ 集合行为不可预测 - IDE 自动生成即可,但注意:如果
id是主键且永不变更,hashCode只基于id计算最安全;别把stock字段加进去——库存变,哈希值就变,对象在HashMap里就“失踪”了
库存增减为什么不能直接用 product.setStock(product.getStock() + delta)?
这是线程不安全的典型写法。即使当前是单线程小系统,这种写法也埋下隐患:一旦未来加定时任务、多线程扫描过期库存,或改成 Web 接口,就会出现超卖或负库存。
- 简单方案:用
synchronized包住整个更新块,锁对象建议用product实例本身(别用this或类锁) - 更稳妥:把库存操作封装进
Product方法,如boolean tryDecrease(int amount),内部检查if (stock >= amount)再减,并返回是否成功 - 别用
AtomicInteger替换int stock——它只保证原子读写,不保证「检查+更新」的原子性(即 ABA 问题仍存在)
JSON 序列化时 LocalDateTime 报错怎么办?
直接用 ObjectMapper 序列化含 LocalDateTime 的 Product,会抛 JsonMappingException: No serializer found。这不是集合问题,是 Jackson 默认不支持 Java 8 时间类型。
立即学习“Java免费学习笔记(深入)”;
- 加依赖:
com.fasterxml.jackson.datatype:jackson-datatype-jsr310 - 注册模块:
ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule());
- 可选:统一格式化,避免前端解析混乱
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Product 的 id 字段是否真的全局唯一?手动拼接、随机数生成、或数据库自增 ID 在纯内存系统里都可能重复——建议用 UUID.randomUUID().toString() 初始化,哪怕多占点内存,也比后期查库存对不上强。










