You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

替换默认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. 上述三种方案更推荐哪一种?
  2. 自定义克隆器的位置在哪?如何开始扩展?

解决方案与建议

方案推荐

  1. 优先选择方案1:将PriorityQueue移至VariableListener是最符合OptaPlanner设计思路的做法。VariableListener的核心作用就是响应规划变量变化,维护衍生计算结果(比如这类需要动态维护的优先级队列)。将队列放在这里,SolutionCloner无需处理它,从根源上避免克隆冲突,同时能保证队列内容随变量变化实时更新。
  2. 若必须在Solution中保留PriorityQueue,选方案3:自定义克隆器能彻底解决类型不匹配问题,且无需改动现有数据结构设计,适合对队列操作性能要求较高的场景。
  3. 方案2作为妥协选项:仅当队列的堆特性(自动排序、O(1)堆顶访问、O(logn)插入删除)并非必须,且排序操作频率极低时使用。转为ArrayList后按需排序的实现成本最低,但频繁排序会带来性能损耗。

自定义SolutionCloner的扩展步骤

默认的FieldAccessingSolutionCloner支持扩展,无需从零编写:

  1. 创建自定义克隆器类:继承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);
    }
}
  1. 配置自定义克隆器:
    • 若使用XML配置:在solverConfig.xml中添加配置项:
      <solver>
          <solutionClonerClass>com.yourpackage.PriorityQueueSupportingSolutionCloner</solutionClonerClass>
          <!-- 其他配置项 -->
      </solver>
      
    • 若使用Java API:通过SolverConfig指定:
      SolverConfig solverConfig = SolverConfig.createFromXmlResource("yourSolverConfig.xml");
      solverConfig.setSolutionClonerClass(PriorityQueueSupportingSolutionCloner.class);
      

内容的提问来源于stack exchange,提问作者Philip Harding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:20:11