2012-11-26 55 views
37

我做了一个调色板,里面有一个jPanel和一个JLabel数组。起初它运行良好,但后来我把一些其他jLabel从JPanel中加入并添加了一些事件。现在,我不断收到此错误:“比较方法违反其总合同!” - TimSort和GridLayout

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色,有没有错误。我真的很好奇发生了什么。任何解释将不胜感激...

+0

看到这个:http://stackoverflow.com/questions/7849539/comparison-method-violates-its-general-contract-java-7-only – mbelow

+1

请注意,这不是一个错误,但删除了一个漏洞。漏洞在于,用于对数组进行排序的比较器可能包含未检测到的逻辑错误。在Java 7中添加了一个检查,如果比较器有错误的行为,此检查现在会输出此错误。由于这可能会产生问题(尽管这可以解决其他问题),但Java 7包含一个强制数组使用先前方法的属性(无比较器验证)。不要指望这个消息随着更新的Java版本而消失。图书馆开发人员必须在代码中解决这个问题 – mins

回答

42

在我看来,你已经打了bug in the JDK因为错误似乎来自Swing类。

选项:

  1. 定义属性java.util.Arrays.useLegacyMergeSorttrue。在你的代码中使用

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

    之前的任何Swing代码。因为main方法的第一行应该工作。

    或(在IDE中,Ant脚本等在控制台,或在项目属性)

  2. 升级你的JDK,看看问题是否加入

    -Djava.util.Arrays.useLegacyMergeSort=true 
    

    到开始的选项消失

  3. 降级到Java 6
+0

我觉得不幸Brian。我刚刚刚接触java,并立即发现错误。你可以向我解释,我将如何运行我的应用程序“-Djava.util.Arrays.useLegacyMergeSort = true”... –

+0

这取决于你如何运行你的应用程序。命令行? Netbeans,Eclipse或其他一些IDE? – madth3

+5

一个普通的选择是将'System.setProperty(“java.util.Arrays.useLegacyMergeSort”,“true”);'作为main方法的第一行。 – madth3

13

报告我的发现:

-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中,那么在程序中设置System属性将不起作用。

我一直在监视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)); 
6

[更新] 这个解决方案很遗憾不能保证解决问题在所有情况下。仅修补KeyboardFocusManager的默认SortingFocusTraversalPolicy 是不够的。

我建议阅读下面的罗宾洛克斯利的答案,包括他的更新。 [/更新]

java.lang.IllegalArgumentException: Comparison method violates its general contract! 
    at java.util.TimSort.mergeHi(TimSort.java:868) 

此问题是由一个错误javax.swing.LayoutComparator引起的。

以下班级安装了javax.swing.LayoutComparator的固定版本,该版本没有违反Comparator<Component>的合同。这个(或任何其他)固定版本的javax.swing.LayoutComparator应该由一些Oracle贡献者提交给Oracle。

package ...; 

import java.awt.Component; 
import java.awt.ComponentOrientation; 
import java.awt.FocusTraversalPolicy; 
import java.awt.KeyboardFocusManager; 
import java.awt.Window; 
import java.lang.reflect.Field; 
import java.util.Comparator; 
import java.util.LinkedList; 
import java.util.ListIterator; 

import javax.swing.JRootPane; 
import javax.swing.SortingFocusTraversalPolicy; 
import javax.swing.UIManager; 

/** 
* Uses reflection to install a fixed version of {@link javax.swing.LayoutComparator} to solve the 
* LayoutFocusTraversalPolicy/TimSort problem. 
* 
* <p> 
* <code>java.lang.IllegalArgumentException: Comparison method violates its general contract!</code> 
* <br/> 
* &nbsp;&nbsp;&nbsp;&nbsp;{@code  at java.util.TimSort.mergeHi(TimSort.java:868)} 
* </p> 
* <p> 
* Usage: call {@code Class.forName(LayoutFocusTraversalPolicyTimSortBugFixer.class.getName())} 
* before creating Swing components. 
* </p> 
* 
* @author Burkhard Strauss 
* @since Feb 2015 
*/ 
public class LayoutFocusTraversalPolicyTimSortBugFixer 
{ 

    static 
    { 
     UIManager.getUI(new JRootPane()); // make Swing install the SortingFocusTraversalPolicy 
     final KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager 
      .getCurrentKeyboardFocusManager(); 
     final FocusTraversalPolicy focusTraversalPolicy = keyboardFocusManager 
      .getDefaultFocusTraversalPolicy(); 
     boolean fixed = false; 
     if (focusTraversalPolicy instanceof SortingFocusTraversalPolicy) 
     { 
     try 
     { 
      final Field field = SortingFocusTraversalPolicy.class.getDeclaredField("comparator"); 
      final boolean accessible = field.isAccessible(); 
      try 
      { 
       field.setAccessible(true); 
       field.set(focusTraversalPolicy, new LayoutComparator()); 
       fixed = true; 
      } 
      finally 
      { 
       field.setAccessible(accessible); 
      } 

     } 
     catch (final Exception e) 
     { 
     } 
     } 
     if (!fixed) 
     { 
     Loggers.getLoggerFor(LayoutFocusTraversalPolicyTimSortBugFixer.class).warn("could not fix the bug"); 
     } 
    } 

    /** 
    * Fixed version of {@link javax.swing.LayoutComparator}. 
    * <p> 
    * Search for 'bugfix' in the code. 
    * </p> 
    * 
    * @author Burkhard Strauss 
    * @since Feb 2015 
    */ 
    @SuppressWarnings("serial") 
    private static class LayoutComparator implements Comparator<Component>, java.io.Serializable 
    { 

     private static final int ROW_TOLERANCE = 10; 

     private boolean horizontal = true; 
     private boolean leftToRight = true; 

     @SuppressWarnings("unused") 
     void setComponentOrientation(final ComponentOrientation orientation) 
     { 
     horizontal = orientation.isHorizontal(); 
     leftToRight = orientation.isLeftToRight(); 
     } 

     @Override 
     public int compare(Component a, Component b) 
     { 
     if (a == b) 
     { 
      return 0; 
     } 

     // Row/Column algorithm only applies to siblings. If 'a' and 'b' 
     // aren't siblings, then we need to find their most inferior 
     // ancestors which share a parent. Compute the ancestory lists for 
     // each Component and then search from the Window down until the 
     // hierarchy branches. 
     if (a.getParent() != b.getParent()) 
     { 
      final LinkedList<Component> aAncestory = new LinkedList<Component>(); 
      for (; a != null; a = a.getParent()) 
      { 
       aAncestory.add(a); 
       if (a instanceof Window) 
       { 
        break; 
       } 
      } 
      if (a == null) 
      { 
       // 'a' is not part of a Window hierarchy. Can't cope. 
       throw new ClassCastException(); 
      } 
      final LinkedList<Component> bAncestory = new LinkedList<Component>(); 
      for (; b != null; b = b.getParent()) 
      { 
       bAncestory.add(b); 
       if (b instanceof Window) 
       { 
        break; 
       } 
      } 
      if (b == null) 
      { 
       // 'b' is not part of a Window hierarchy. Can't cope. 
       throw new ClassCastException(); 
      } 
      for (ListIterator<Component> aIter = aAncestory.listIterator(aAncestory.size()), bIter = bAncestory 
        .listIterator(bAncestory.size());;) 
      { 
       if (aIter.hasPrevious()) 
       { 
        a = aIter.previous(); 
       } 
       else 
       { 
        // a is an ancestor of b 
        return -1; 
       } 
       if (bIter.hasPrevious()) 
       { 
        b = bIter.previous(); 
       } 
       else 
       { 
        // b is an ancestor of a 
        return 1; 
       } 
       if (a != b) 
       { 
        break; 
       } 
      } 
     } 

     final int ax = a.getX(), ay = a.getY(), bx = b.getX(), by = b.getY(); 
     int zOrder = a.getParent().getComponentZOrder(a) - b.getParent().getComponentZOrder(b); 
     { 
      // 
      // Here is the bugfix: 
      // Don't return 0 if a != b. This would violate the contract of 
      // Comparator<Component>.compare(). 
      // 
      if (zOrder == 0) 
      { 
       zOrder = -1; 
      } 
     } 
     if (horizontal) 
     { 
      if (leftToRight) 
      { 

       // LT - Western Europe (optional for Japanese, Chinese, Korean) 

       if (Math.abs(ay - by) < ROW_TOLERANCE) 
       { 
        return (ax < bx) ? -1 : ((ax > bx) ? 1 : zOrder); 
       } 
       else 
       { 
        return (ay < by) ? -1 : 1; 
       } 
      } 
      else 
      { // !leftToRight 

       // RT - Middle East (Arabic, Hebrew) 

       if (Math.abs(ay - by) < ROW_TOLERANCE) 
       { 
        return (ax > bx) ? -1 : ((ax < bx) ? 1 : zOrder); 
       } 
       else 
       { 
        return (ay < by) ? -1 : 1; 
       } 
      } 
     } 
     else 
     { // !horizontal 
      if (leftToRight) 
      { 

       // TL - Mongolian 

       if (Math.abs(ax - bx) < ROW_TOLERANCE) 
       { 
        return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder); 
       } 
       else 
       { 
        return (ax < bx) ? -1 : 1; 
       } 
      } 
      else 
      { // !leftToRight 

       // TR - Japanese, Chinese, Korean 

       if (Math.abs(ax - bx) < ROW_TOLERANCE) 
       { 
        return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder); 
       } 
       else 
       { 
        return (ax > bx) ? -1 : 1; 
       } 
      } 
     } 
     } 
    } 
} 
3

我刚碰到相同的错误,并花了大量的时间跟踪它。为了帮助那些遇到这个错误的人,了解如何测试TimSort非常重要。违反传递性契约并抛出此错误的检查在算法中很深,并且在再现该问题之前需要进行测试以满足特定标准。

  1. 创建一个包含32个或更多对象的列表。
  2. 在该列表中,需要两次或多次运行。
  3. 每次运行必须包含3个或更多对象。

一旦你符合这两个标准,你就可以开始测试这个失败。

运行被定义为列表的子集,其中每个项目已经处于期望的有序状态。

0

仅仅将LayoutComparator修补为上面的suggerested是不够的。这个修补程序在我的情况下不起作用。 该问题已在JDK 8中修复(至少8u45)。 SortingFocusTraversalPolicy使用传统的合并排序方法。

相关问题