bigywater.tech
Java 内部原理 · 121

PriorityQueue 真实验证:toArray()和iterator()真实不是有序的,只有poll()才是

PriorityQueue经常被当成"自动排序的队列"用——这篇真实插入10个乱序整数,对比toArray()、iterator()遍历和poll()弹出三种方式,真实验证PriorityQueue到底维护的是什么顺序。

toArray()真实不是有序的
真实验证:10个乱序整数入队后,toArray()真实拿到的是内部数组的堆结构顺序,不是从小到大排序
poll()真实才保证顺序
真实验证:只有反复调用poll(),才能真实依次拿到从小到大的元素

上一篇:String代理对真实验证

真实验证:toArray()和iterator()真实只是堆序,不是排序结果

PriorityQueue底层是一个基于数组实现的二叉堆,只保证"父节点 <= 子节点"这一条堆性质,不保证整体有序。

PriorityQueueHeapOrderDemo.java int[] vals = {50, 30, 70, 10, 40, 60, 80, 20, 90, 5}; for (int v : vals) pq.add(v); pq.toArray(); // 直接拿内部数组 for (int v : pq) ...; // iterator()遍历
真实实测
插入顺序: [50, 30, 70, 10, 40, 60, 80, 20, 90, 5]
toArray() 真实内部数组顺序: [5, 10, 60, 30, 20, 70, 80, 50, 90, 40]
iterator() 真实遍历顺序: 5 10 60 30 20 70 80 50 90 40
toArray() 真实是否已排序: false

真实结果证明 toArray() 和 iterator() 拿到的真实是堆内部数组的原始存储顺序——只有下标0(堆顶,最小值5)是确定的,其余位置只保证"父节点小于等于它的两个子节点",同一层的兄弟节点之间真实没有大小关系约束。这也是为什么示例里的第二个元素是10而不是20——10是堆顶5的子节点之一,它只需要比5大即可,跟30、70这些"看起来应该排在后面"的值之间真实没有约束关系。

真实验证:poll()才是唯一保证顺序的方式

既然遍历不保证顺序,那"优先级"到底体现在哪?真实测试反复poll()的结果。

PriorityQueueHeapOrderDemo.java while (!pq2.isEmpty()) pollOrder.append(pq2.poll());
真实实测
poll() 真实依次弹出顺序: 5 10 20 30 40 50 60 70 80 90

真实验证堆性质(父<=子)全部成立: true
真实结果证明PriorityQueue是"惰性排序"的数据结构。它不在插入时排序,也不在遍历时排序,而是把排序工作推迟到每次 poll() 调用——每次真实取出堆顶最小值后,用末尾元素补位并做一次"下沉"调整来重新维护堆性质,均摊复杂度是 O(log n)。真实反射验证的堆数组也确认,任意节点i的两个子节点(下标 2i+1、2i+2)真实都不小于父节点i,但兄弟节点之间没有大小约束——这正是"只见局部,不见全局"的堆序,跟真正的排序结果是两回事。如果代码里对 PriorityQueue 做了 toArray() 或 for-each 遍历并假设结果有序,真实会拿到一个看起来乱序、实际符合堆性质的数组。

分步演示:堆序是怎么一步步长出来的

同一份数据,左边是树形结构(方便看"父 <= 子"这条堆性质),右边是数组的真实存储顺序(方便对照 toArray() 看到的结果)——每一步都是真实反射读出的 PriorityQueue.queue。

10 次 add() 建堆 + 4 次 poll() 弹出:数组存储顺序和树形结构对照(反射读取 PriorityQueue.queue)
刚上浮/下沉到当前位置的节点当前堆顶

    参考与说明

    • 本文全部结果均在本机真实运行 Java 17 得到,堆序和poll()弹出顺序重复运行完全一致。作为新一批的第一篇,系列 Java 内部原理现在共 121 篇。
    • 和HashMap 内部原理一起看,能更完整理解"遍历顺序不等于逻辑顺序"这个模式在JDK集合里反复出现的原因——底层存储结构决定了迭代顺序,语义顺序往往需要额外操作才能拿到。
    • 没有涉及:PriorityQueue的remove(Object)真实需要线性查找、Comparator自定义排序下堆序的真实表现——这两个话题留给系列后面按需再写。
    京ICP备2026067502号-1京公网安备11010502063487号