在Java中如何开发小型商品库存管理系统_Java集合与对象解析

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

ArrayList 还是 HashMap 存商品?看查询场景

库存系统最常查的是「根据商品编号找商品」或「遍历所有商品做盘点」。如果频繁按 id 查,HashMapArrayList 快得多——前者平均 O(1),后者要遍历,最坏 O(n)。但若主要做批量入库、按顺序打印报表,ArrayList 更省内存、遍历更缓存友好。

  • 单商品查改多 → 优先用 HashMap,key 设为 String id(别用 int,避免装箱/溢出)
  • 需保持插入顺序或导出 Excel 时按录入顺序排列 → 保留 ArrayList 副本,或直接用 LinkedHashMap
  • 别把 Product 对象塞进 TreeMap 除非真要按价格/名称排序——它额外开销大,且 compareTo 写错会导致 put 失效

Product 类必须重写 equalshashCode 吗?

必须。否则放进 HashSet 或作为 HashMap 的 value 时,哪怕两个对象字段完全一样,contains 也会返回 false;用 remove 删不掉;甚至同一对象 add 两次都成功。

  • 只重写 equals 不重 hashCodeHashMap 查不到
  • 只重 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 ——它只保证原子读写,不保证「检查+更新」的原子性(即 AB

    A 问题仍存在)

JSON 序列化时 LocalDateTime 报错怎么办?

直接用 ObjectMapper 序列化含 LocalDateTimeProduct,会抛 JsonMappingException: No serializer found。这不是集合问题,是 Jackson 默认不支持 Java 8 时间类型。

  • 加依赖: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"));
实际运行中,最容易被忽略的是:Productid 字段是否真的全局唯一?手动拼接、随机数生成、或数据库自增 ID 在纯内存系统里都可能重复——建议用 UUID.randomUUID().toString() 初始化,哪怕多占点内存,也比后期查库存对不上强。