替换默认SolutionCloner:PriorityQueue克隆异常的方案选择与扩展疑问
问题描述
在包含实体类的规划问题中,于问题类中声明多个PriorityQueue后,运行时抛出异常:
Exception in thread "main" java.lang.IllegalStateException: The cloneCollectionClass (class java.util.ArrayList) created for originalCollectionClass (class java.util.PriorityQueue) is not assignable to the field's type (class java.util.PriorityQueue). Maybe consider replacing the default SolutionCloner.
根据官方手册说明:
当FieldAccessingSolutionCloner克隆集合或映射时,若无法识别实现类,会替换为ArrayList、LinkedHashSet等常用JDK实现,它仅支持多数常见JDK集合与映射实现。
PriorityQueue不在默认支持列表中,且不属于标准Collection接口。本人总结三种解决方案:
- 将
PriorityQueue放置在自定义VariableListener中(每个规划事实对应一个,可存入Map),确保VariableListener被正确触发; - 放弃使用PriorityQueue,全部转为
ArrayList,在自定义VariableListener中按需排序(如Arrays.sort(pq.toArray())); - 按错误提示创建自定义
SolutionCloner,但希望通过扩展默认实现而非从零编写。
现有两个疑问:
- 上述三种方案更推荐哪一种?
- 自定义克隆器的位置在哪?如何开始扩展?
解决方案与建议
方案推荐
- 优先选择方案1:将
PriorityQueue移至VariableListener是最符合OptaPlanner设计思路的做法。VariableListener的核心作用就是响应规划变量变化,维护衍生计算结果(比如这类需要动态维护的优先级队列)。将队列放在这里,SolutionCloner无需处理它,从根源上避免克隆冲突,同时能保证队列内容随变量变化实时更新。 - 若必须在Solution中保留PriorityQueue,选方案3:自定义克隆器能彻底解决类型不匹配问题,且无需改动现有数据结构设计,适合对队列操作性能要求较高的场景。
- 方案2作为妥协选项:仅当队列的堆特性(自动排序、O(1)堆顶访问、O(logn)插入删除)并非必须,且排序操作频率极低时使用。转为ArrayList后按需排序的实现成本最低,但频繁排序会带来性能损耗。
自定义SolutionCloner的扩展步骤
默认的FieldAccessingSolutionCloner支持扩展,无需从零编写:
- 创建自定义克隆器类:继承
FieldAccessingSolutionCloner,重写处理集合/队列的逻辑:
public class PriorityQueueSupportingSolutionCloner extends FieldAccessingSolutionCloner { @Override protected <T> Collection<T> cloneCollection(Collection<T> originalCollection) { if (originalCollection instanceof PriorityQueue) { // 复制原PriorityQueue的元素和比较器 return new PriorityQueue<>((PriorityQueue<T>) originalCollection); } // 其他集合类型沿用默认逻辑 return super.cloneCollection(originalCollection); } }
- 配置自定义克隆器:
- 若使用XML配置:在
solverConfig.xml中添加配置项:<solver> <solutionClonerClass>com.yourpackage.PriorityQueueSupportingSolutionCloner</solutionClonerClass> <!-- 其他配置项 --> </solver> - 若使用Java API:通过
SolverConfig指定:SolverConfig solverConfig = SolverConfig.createFromXmlResource("yourSolverConfig.xml"); solverConfig.setSolutionClonerClass(PriorityQueueSupportingSolutionCloner.class);
- 若使用XML配置:在
内容的提问来源于stack exchange,提问作者Philip Harding
相关产品推荐
相关产品推荐

