“比较法违反了它的总契约!” \- TimSort 和 GridLayout

新手上路,请多包涵

我制作了一个带有 jPanel 和 JLabel 数组的调色板。起初它运行良好,但后来我将一些其他 jLabel 从 JPanel 中取出并添加了一些事件。现在我不断收到此错误:

 Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:747)
at java.util.TimSort.mergeAt(TimSort.java:483)
at java.util.TimSort.mergeCollapse(TimSort.java:410)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:136)
at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(SortingFocusTraversalPolicy.java:110)
at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:435)
at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:166)
at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(SortingFocusTraversalPolicy.java:515)
at java.awt.FocusTraversalPolicy.getInitialComponent(FocusTraversalPolicy.java:169)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:380)
at java.awt.Component.dispatchEventImpl(Component.java:4731)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:723)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:682)
at java.awt.EventQueue$3.run(EventQueue.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:696)
at java.awt.EventQueue$4.run(EventQueue.java:694)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:693)
at java.awt.SequencedEvent.dispatch(SequencedEvent.java:116)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:721)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:682)
at java.awt.EventQueue$3.run(EventQueue.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:696)
at java.awt.EventQueue$4.run(EventQueue.java:694)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:693)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

我试图删除我第一次收到此错误后所做的一切,但仍然继续收到它。当我将布局从 GridLayout 更改为其他布局时,错误消失,但代码变得无用。所以我需要 GridLayout。当我将该 JPanel 中的所有内容移动到另一个 JPanel 时,错误也会消失。但是当我删除第一个 JPanel 时,错误又回来了。

顺便说一句,该程序可以运行,但不断出现错误并不令人愉快……

编辑:当我使用少于 225 种颜色时,没有错误。我真的很好奇发生了什么。任何解释将不胜感激……

原文由 s.alem 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 621
2 个回答

在我看来,您似乎遇到 了 JDK 中 的错误,因为该错误似乎来自 Swing 类。

选项:

  1. 将属性 java.util.Arrays.useLegacyMergeSort 定义为 true 。在您的代码中使用该行
   System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

在任何 Swing 代码之前。作为 main 方法中的第一行应该有效。

或添加

   -Djava.util.Arrays.useLegacyMergeSort=true

到您的启动选项(在控制台中,或在 IDE、Ant 脚本等的项目属性中)

  1. 升级您的 JDK 并查看问题是否消失

  2. 降级到 Java 6

原文由 madth3 发布,翻译遵循 CC BY-SA 4.0 许可协议

报告我的发现:

 -Djava.util.Arrays.useLegacyMergeSort=true

作品

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

不起作用。

这是因为在 JDK Arrays.class 中

 static final class LegacyMergeSort {
    private static final boolean userRequested = ...

它是一个静态变量,在 jvm 启动时定义。如果该类已加载到 jvm 中,则在程序中设置系统属性将不起作用。

我一直在监视 LegacyMergeSort.userRequested 变量,并且发现结果与上述声明一致。

更新:程序必须在 java.util.Arrays 加载到类加载器之前设置系统属性。否则,一旦加载,由于上述原因,设置属性将无用。

确保没有加载任何其他 Arrays.class:

通过将以下代码放入您的程序中进行测试:

     java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] { String.class });
    m.setAccessible(true);
    ClassLoader cl = ClassLoader.getSystemClassLoader();
    Object test1 = m.invoke(cl, "java.util.Arrays");
    System.out.println("test1 loaded? ->" + (test1 != null));

原文由 Robin Loxley 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题