无法实例化类型Map<String,Boolean>

本文详细介绍了在Java编程中遇到无法实例化抽象接口Map<String, Boolean>的问题,并提供了正确的实现方式,即使用其具体实现类HashMap。通过实例演示,帮助开发者避免常见错误并提高代码效率。

无法实例化类型Map<String,Boolean>

错误代码:

[java]  view plain copy
  1. Map<String, Boolean> modelPropertys = new Map<String, Boolean>();  

看了一下Map的定义,public abstract interface java.util.Map

原来是抽象接口,不能直接实例化,需要使用它的实现类;

正确写法如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Map<String, Boolean> modelPropertys = new HashMap<String, Boolean>();  
/** * 快照类:保存排程状态副本 */ public static class ScheduleSnapshot { private final Map<String, Map<Date, BigDecimal>> remainingTimeMap; private final Set<String> filledClasses; private final Map<String, Set<String>> filledClasses2; private final Map<String, Set<String>> deviceOccupyMap; private final Map<String, List<PpMachiningOrderList>> assignedCache; private final Map<String, Map<Date, List<String>>> tem; public ScheduleSnapshot( Map<String, Map<Date, BigDecimal>> remainingTimeMap, Set<String> filledClasses, Map<String, Set<String>> filledClasses2, Map<String, Set<String>> deviceOccupyMap, Map<String, List<PpMachiningOrderList>> assignedCache, Map<String, Map<Date, List<String>>> tem) { this.remainingTimeMap = deepCopyRemainingTimeMap(remainingTimeMap); this.filledClasses = new HashSet<>(filledClasses); this.filledClasses2 = deepCopyFilledClasses2(filledClasses2); this.deviceOccupyMap = deepCopyFilledClasses2(deviceOccupyMap); this.assignedCache = deepCopyAssignedCache(assignedCache); this.tem = deepCopyTem(tem); } private Map<String, Map<Date, BigDecimal>> deepCopyRemainingTimeMap(Map<String, Map<Date, BigDecimal>> src) { return src.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> new HashMap<>(e.getValue()))); } private Map<String, Set<String>> deepCopyFilledClasses2(Map<String, Set<String>> src) { return src.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> new HashSet<>(e.getValue()))); } private Map<String, Map<Date, List<String>>> deepCopyTem(Map<String, Map<Date, List<String>>> src) { return src.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, innerE -> new ArrayList<>(innerE.getValue()))) )); } private Map<String, List<PpMachiningOrderList>> deepCopyAssignedCache(Map<String, List<PpMachiningOrderList>> src) { return src.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> new ArrayList<>(e.getValue()) // 浅拷贝:新建 list,但对象引用相同 )); } /** * 恢复所有状态 */ public void restore( Map<String, Map<Date, BigDecimal>> remainingTimeMap, Set<String> filledClasses, Map<String, Set<String>> filledClasses2, Map<String, Map<Date, List<String>>> tem, Map<String, Set<String>> deviceOccupyMap, Map<String, List<PpMachiningOrderList>> assignedCache) { remainingTimeMap.clear(); remainingTimeMap.putAll(this.remainingTimeMap); filledClasses.clear(); filledClasses.addAll(this.filledClasses); filledClasses2.clear(); filledClasses2.putAll(this.filledClasses2); tem.clear(); tem.putAll(this.tem); deviceOccupyMap.clear(); deviceOccupyMap.putAll(this.deviceOccupyMap); assignedCache.clear(); assignedCache.putAll(this.assignedCache); } }解析
最新发布
12-17
你提供的代码是一个 **排程快照类 `ScheduleSnapshot`**,用于在任务调度过程中保存当前状态的“深拷贝”,以便后续可以回滚到该状态。这在回溯算法、试探性排程、撤销操作等场景中非常常见。 下面我将 **逐行解析这个类的设计与实现**,解释其作用、每个字段的意义、拷贝方式的选择以及为何要这样设计。 --- ## ✅ 类总览 ```java public static class ScheduleSnapshot { // 保存多个状态映射的副本 private final Map<String, Map<Date, BigDecimal>> remainingTimeMap; private final Set<String> filledClasses; private final Map<String, Set<String>> filledClasses2; private final Map<String, Set<String>> deviceOccupyMap; private final Map<String, List<PpMachiningOrderList>> assignedCache; private final Map<String, Map<Date, List<String>>> tem; // 构造函数:深拷贝传入的所有状态 public ScheduleSnapshot(...) // 恢复方法:把快照中的数据写回原始对象 public void restore(...) } ``` 这是一个典型的 **Memento(备忘录)模式** 的应用:保存系统某一时刻的状态,供之后恢复使用。 --- ## 🧩 字段详解(每个字段代表什么?) | 字段 | 类型 | 含义 | |------|------|------| | `remainingTimeMap` | `Map<String, Map<Date, BigDecimal>>` | 表示某种资源(如设备、工序)在不同日期的剩余可用时间。例如:`"MachineA"` → `Date: 剩余工时(BD)` | | `filledClasses` | `Set<String>` | 已被“填满”的类别集合(可能是班次、班组、产线等),一旦填满就不允许再分配任务 | | `filledClasses2` | `Map<String, Set<String>>` | 更复杂的填充关系,比如 `"Line1"` → `{"ShiftA", "ShiftB"}`,表示某条线上哪些班次已满 | | `deviceOccupyMap` | `Map<String, Set<String>>` | 设备占用情况,如 `"DeviceX"` → `{"Order123", "Order456"}`,记录哪些订单占用了该设备 | | `assignedCache` | `Map<String, List<PpMachiningOrderList>>` | 缓存已分配的任务,按 key 分组(可能是设备、工人、工序),保存当前已安排的加工单列表 | | `tem` | `Map<String, Map<Date, List<String>>>` | 临时结构,可能用于存储每日排班或临时占位信息,如 `"WorkerGroup"` → `Date → ["Order1", ...]` | 这些字段共同构成了一个 **完整的排程上下文状态**。 --- ## 🔐 构造函数:为什么要做深拷贝? 构造函数接收原始状态,并通过一系列 `deepCopyXxx()` 方法进行 **深度复制**,确保: > 快照中的数据独立于原对象,后续修改不会互相影响。 ### ❗关键点:浅拷贝 vs 深拷贝 如果不做深拷贝,只复制引用,那么当你修改原始数据时,快照里的数据也会变 —— 这是灾难性的! 所以必须层层拷贝到底层可变对象。 --- ## 🔍 各 `deepCopy` 方法详解 ### 1. `deepCopyRemainingTimeMap` ```java private Map<String, Map<Date, BigDecimal>> deepCopyRemainingTimeMap(Map<String, Map<Date, BigDecimal>> src) { return src.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> new HashMap<>(e.getValue()) // 第二层 map 是新 HashMap )); } ``` ✅ **双层深拷贝完成**: - 外层 key 不变(String) - 内层 `Map<Date, BigDecimal>` 是新建的,不影响原 map 📌 注意:`BigDecimal` 是不可变对象,无需再拷贝。 --- ### 2. `deepCopyFilledClasses2` 和 `deviceOccupyMap` ```java private Map<String, Set<String>> deepCopyFilledClasses2(Map<String, Set<String>> src) { return src.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> new HashSet<>(e.getValue()) )); } ``` ✅ 对 `Map<String, Set<String>>` 类型做了深拷贝: - 外层 map 新建 - 每个 value(Set)也是新的 HashSet ⚠️ 注意:`deviceOccupyMap` 使用了相同的拷贝方法,说明它和 `filledClasses2` 结构一致。 --- ### 3. `deepCopyTem` ```java private Map<String, Map<Date, List<String>>> deepCopyTem(Map<String, Map<Date, List<String>>> src) { return src.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, innerE -> new ArrayList<>(innerE.getValue()) )) )); } ``` ✅ 三层结构全部深拷贝: - 外层:`String → Map` - 中间层:`Date → List` - 最内层:`List<String>` 是新 ArrayList 📌 `String` 不可变,无需拷贝;但 `List` 可变,必须新建。 --- ### 4. `deepCopyAssignedCache` ```java private Map<String, List<PpMachiningOrderList>> deepCopyAssignedCache(Map<String, List<PpMachiningOrderList>> src) { return src.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> new ArrayList<>(e.getValue()) // 浅拷贝:新建 list,但对象引用相同 )); } ``` ❗注意注释:“**浅拷贝:新建 list,但对象引用相同**” 这意味着: - 列表本身是新的(你可以增删不影响原列表) - 但里面的 `PpMachiningOrderList` 对象是同一个实例! 👉 是否安全取决于业务逻辑: | 场景 | 是否安全 | |------|---------| | 只读访问这些对象 | ✅ 安全 | | 修改对象内部字段(如 setQty, setStatus) | ❌ 危险!会影响原状态 | 🔧 如果需要完全隔离,应实现对象克隆(如序列化拷贝、手动 new 或使用 BeanUtils.copyProperties 等) --- ## 💾 `restore()` 方法:如何恢复状态? ```java public void restore( Map<String, Map<Date, BigDecimal>> remainingTimeMap, Set<String> filledClasses, Map<String, Set<String>> filledClasses2, Map<String, Map<Date, List<String>>> tem, Map<String, Set<String>> deviceOccupyMap, Map<String, List<PpMachiningOrderList>> assignedCache) { // 清空原始容器,然后放入快照中的副本 remainingTimeMap.clear(); remainingTimeMap.putAll(this.remainingTimeMap); filledClasses.clear(); filledClasses.addAll(this.filledClasses); // ... 其他类似 } ``` ✅ 恢复策略: - 所有外部传入的“状态容器”都被清空 - 然后用快照中的副本重新填充 📌 这是一种 **整体替换式恢复**,适用于你在尝试某个排程分支失败后想“回到上一个稳定状态”。 --- ## 🎯 使用场景举例 ```java // 保存当前状态 ScheduleSnapshot snapshot = new ScheduleSnapshot(remainingTimeMap, filledClasses, ..., assignedCache); try { // 尝试排程某些订单 boolean success = tryScheduleSomeOrders(...); if (!success) { // 回滚! snapshot.restore(remainingTimeMap, filledClasses, ..., assignedCache); } } catch (Exception e) { // 出错也回滚 snapshot.restore(...); } ``` 这在以下场景特别有用: - 排程试探失败需回退 - 支持“撤销”功能 - 多路径搜索最优解(回溯法) --- ## ✅ 总结:优点与建议 ### ✔️ 优点 | 特性 | 说明 | |------|------| | **状态隔离** | 通过深拷贝避免共享可变状态 | | **恢复能力** | 支持完整状态回滚 | | **结构清晰** | 字段命名规范,职责明确 | | **扩展性强** | 易于添加新状态字段 | ### ⚠️ 可改进点 1. **`assignedCache` 的浅拷贝风险** - 建议增加注释警告:“若修改 PpMachiningOrderList 实例字段会导致状态污染” - 或者改为深拷贝(如果对象不多): ```java e.getValue().stream().map(deepCopyOrder).collect(Collectors.toList()) ``` 2. **性能考虑** - 深拷贝成本高,频繁创建快照会影响性能 - 可考虑差量备份(只记录变化部分) 3. **Date 的不可变性问题** - `Date` 是可变对象(非 final),虽然这里没改,但建议未来用 `LocalDateTime` 4. **泛型提取成工具类** - 很多深拷贝逻辑可以封装为通用工具方法,如: ```java CollectionUtils.deepCopyMap(map, HashSet::new); ``` --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值