基础购物车用ArrayList存商品、Scanner接收输入,需封装Product类(含id/name/price/quantity),重写equals()/hashCode(),用序号删除、价格用int存分单位、输入后调nextLine()清缓存,总价格式化输出。

怎么用 Scanner + ArrayList 搭出基础购物车结构
控制台购物车本质是内存中的数据管理,不需要数据库或 Web 框架。核心就是用 ArrayList 存商品,用 Scanner 接收用户输入。别一上来就搞类图或 MVC 分层——先跑通“加商品→查清单→删一项→算总价”这四个动作。
关键点在于:商品最好封装成独立类(比如 Product),至少含 id、name、price、quantity 四个字段;购物车本身用 ArrayList,而不是存字符串或数组。否则后续修改数量、按 ID 查找会非常痛苦。
常见错误:
• 把价格用 int 存(导致 9.9 元变成 9 元)→ 改用 double 或更稳妥的 BigDecimal(初级项目用 double 即可)
• 每次添加都 new 一个新 Product,但没重写 equals() → 后续删商品时用 list.remove(product) 失败
• Scanner 读完数字后没调 nextLine() 清缓存 → 下一次 nextLine() 直接返回空字符串
怎么处理用户反复输入和菜单跳转逻辑
控制台交互最易崩的地方不是功能,而是输入流错乱。别用一堆 if-else if 堆菜单,用 while (true) + switch 主循环更清晰。每次循环开头先打印菜单,结尾统一用 scanner.nextLine() 吃掉换行符。
立即学习“Java免费学习笔记(深入)”;
实操建议:
• 输入选项用 scanner.nextInt(),但之后立刻跟 scanner.nextLine()
• 所有字符串输入(如商品名)统一用 scanner.nextLine().trim(),避免空格导致匹配失败
• 输入非法数字时,hasNextInt() 比直接 try-catch 更轻量;如果用户输 “abc” 再输 “1”,不清理输入缓冲区会导致死循环
• 退出选项设为 0 或 “quit”,在 switch 外围用 break outer; 或设标志位 running = false
怎么安全地从购物车删除指定商品
初学者常写 cart.remove(product),结果删不掉——因为两个 Product 对象内存地址不同,即使字段一样,equals() 默认比较的是引用。必须重写 equals() 和 hashCode(),且至少基于 id 判断相等性。
更实用的做法(尤其对初级项目):
• 提供按序号删除:遍历 cart,用 for (int i = 0; i ,打印时带上 i + 1 作为序号
• 用户输入序号 n,校验 n > 0 && n ,然后 cart.remove(n - 1)
• 避免用商品名删除(重名情况难处理),也别用价格删(多个商品同价很常见)
• 删除后记得提示“已移除:xxx”,并立即调用显示清单方法,让用户确认
为什么结算时总价总是不对?浮点精度和累加陷阱
用 double price = 29.99; 累加多次后输出可能是 89.96999999999999。这不是 bug,是二进制浮点数表示局限。初级项目不用上 BigDecimal,但至少得格式化输出:
System.out.printf("总计:¥%.2f\n", total);
但注意:printf 只影响显示,不修正计算过程。如果要做“满 100 减 10”这类判断,不能写 if (total >= 100.0),而应写 if (Math.abs(total - 100.0) 100.0),或更简单——所有价格内部乘 100 存 int(如 2999 表示 29.99 元),运算完再除 100.0 输出。后者对初学者更可控,也避开了 BigDecimal 的构造参数陷阱(比如 new BigDecimal(29.99) 实际是 29.989999999999998...)。
真正容易被忽略的是:用户反复添加同一商品时,应该合并数量而非新增一条记录。这需要在添加前遍历检查 cart 中是否存在相同 id 的商品——这里又回到必须重写 equals() 的问题。










