2016-02-01 5 views
0

я получил исключениепочему Компаратор <Integer[]> выбрасывает исключение?

java.lang.IllegalArgumentException: Comparison method violates its general contract! 
at java.util.TimSort.mergeHi(TimSort.java:868) 
at java.util.TimSort.mergeAt(TimSort.java:485) 
at java.util.TimSort.mergeCollapse(TimSort.java:408) 
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 Main.main(Main.java:64) 

при использовании этого кода:

Arrays.sort(arr, new Comparator<Integer[]>(){ //arr is 2D array 
     public int compare(Integer[] o1, Integer[] o2){ 
      return o1[2]==o2[2]?0:o1[2]>o2[2]?1:-1; 
     } 
    }); 

, который я считаю, связан с не удовлетворяющей транзитивностью сравнения, но когда я сделал небольшое изменение, как это:

Arrays.sort(arr, new Comparator<Integer[]>(){ //arr is 2D array 
     public int compare(Integer[] o1, Integer[] o2){ 
      return o1[2].compareTo(o2[2]); // here is the change 
     } 
    }); 

исключение больше не сгенерировано. я не могу понять объяснение этого вопроса, как я уверен, что экземпляр Integer можно сравнить с использованием реляционных операторов (>, < =) кроме того CompareTo() метод

Integer x = 1; 
Integer y = 2; 
System.out.println(x<y); 

печатает правда, как и ожидалось

Может ли любое тело прояснить?

+0

http://stackoverflow.com/questions/8327514/comparison-method-violates-its-general-contract –

+1

«Целочисленные» экземпляры * не сравниваются * с использованием реляционных операторов. Сначала подразумевается неявное распаковка. –

+0

Каково содержимое ваших массивов? Существуют ли какие-либо значения вне [Целочисленный диапазон кеша] (https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf-int-)? – rgettman

ответ

7

Проблема с:

o1[2]==o2[2] 

Это сравнение Integer с для идентичности. Равные экземпляры необязательно идентичны. Например:

Integer a = new Integer(128); 
Integer b = new Integer(128); 
System.out.println(a == b);  // False, instances are not identical. 
System.out.println(a.equals(b)); // True, instances are equal. 

Оно должно быть:

o1[2].equals(o2[2]) 

Или обрабатывать o1[2] быть null:

Objects.equal(o1[2], o2[2]) 
1

, так как вы используете Integer и не Int, это не действует:

o1[2]==o2[2]?0:o1[2]>o2[2]?1:-1; 

вам нужно использовать equals или compareTo, не ==

0

Массив вы сортировка, составленный из Integer объектов. Они отличаются от простых старых целых чисел.

Простое старое целое число, просто сидящее в памяти.

Объект Integer является экземпляром класса, который выполняет ту же роль, что и базовое целое число, но также имеет множество методов и данных, связанных с ним. В этом разница между тем, чтобы быть частью данных или быть объектом.

Оператор == сравнивает цифры в памяти. В случае экземпляра объекта он будет сравнивать места в памяти, а не значения чисел, которые вы планируете использовать.

Для объектов Integer (и других числовых объектов) вместо этого вы должны использовать метод compareTo().

Ваше решение здесь либо использовать метод compareTo(), как предлагается, либо изменить массив на простые старые целые числа.

Вы также можете оставить его как объекты Integer, а затем использовать Integer.intValue() для получения простого старого целого числа, а затем вы можете использовать сравнение ==. Но это довольно запутанно, ИМО.