我制作了一个带有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色时,没有错误。我真的很好奇发生了什么。任何解释都将不胜感激......
答案 0 :(得分:42)
在我看来,你似乎已经点击了bug in the JDK,因为错误似乎来自Swing课程。
选项:
将属性java.util.Arrays.useLegacyMergeSort
定义为true
。在代码中使用
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
在任何Swing代码之前。因为main
方法中的第一行应该有效。
或添加
-Djava.util.Arrays.useLegacyMergeSort=true
到你的起始选项(在控制台中,或IDE,Ant脚本中的项目属性等)
升级JDK并查看问题是否消失
答案 1 :(得分: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));
答案 2 :(得分:6)
<强> [更新] 强> 遗憾的是,这种解决方案无法在所有情况下解决问题。修补默认的SortingFocusTraversalPolicy是不够的 的KeyboardFocusManager。
我建议在下面阅读Robin Loxley的答案,包括他的更新。 的 [/更新] 强>
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/>
* {@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 :(得分:5)
我遇到了同样的错误,花了很多时间跟踪它。为了帮助遇到此错误的其他人,了解如何测试TimSort非常重要。违反传递性合同并抛出此错误的检查在算法中很深入,并且在重现此问题之前需要进行测试以满足某些条件。
一旦达到这两个标准,就可以开始测试此失败。
运行被定义为列表的子集,其中每个项目已处于所需的有序状态。
答案 4 :(得分:0)
将LayoutComparator修补为上面的补充是不够的。此修复程序在我的情况下不起作用。 该问题已在JDK 8(至少8u45)中修复。 SortingFocusTraversalPolicy使用旧版合并排序方法。