下面这段代码使用了 compareTo()
方法,有问题吗?
1 2 3 4 5 6 7 8 9
| class Employee implements Comparable { private int id;
@Override public int compareTo(Object o) { Employee emp = (Employee) o; return this.id - emp.id; } }
|
使用减法看起来合乎逻辑,但实际上隐藏了溢出的问题。
当我们需要按照一定的规则进行排序的时候,通常要实现 Comparable
接口,并实现 compareTo
方法,规则如下:
1)如果当前对象小于另外一个对象,则 compareTo
方法必须返回负数;如果当前对象大于另外一个对象,则必须返回正数;如果两个对象相等,则返回零。
2)通常来说,compareTo
方法必须和 equals
方法一致,如果两个对象通过 equals 方法判断的结果为 true
,那么 compareTo
必须返回零。
不过,JDK 中有一个反例,就是 BigDecimal
。
1 2 3 4 5
| BigDecimal bd1 = new BigDecimal("2.0"); BigDecimal bd2 = new BigDecimal("2.00");
System.out.println("equals: " + bd1.equals(bd2)); System.out.println("compareTo: " + bd1.compareTo(bd2));
|
输出结果如下所示:
1 2
| equals: false compareTo: 0
|
这是因为 JDK
认为 2.0
和 2.00
的精度不一样,所以不能 equals
,但值确实是相等的。
3)不能使用减法来比较整数值,因为减法的结果可能溢出。应该使用 Integer.compareTo()
来进行比较。如果你想通过减法操作来提高性能,必须得确保两个操作数是正整数,或者确保两者相差的值小于 Integer.MAX_VALUE
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class CompareDemo { public static void main(String[] args) { List<Employee> list = new ArrayList<>(); list.add(new Employee(1)); list.add(new Employee(Integer.MIN_VALUE)); list.add(new Employee(Integer.MAX_VALUE)); Collections.sort(list); System.out.println(list); } }
class Employee implements Comparable { private int id;
public Employee(int id) { this.id = id; }
@Override public int compareTo(Object o) { Employee emp = (Employee) o; return this.id - emp.id; }
@Override public String toString() { return "Employee{" + "id=" + id + '}'; } }
|
程序的输出结果如下所示:
1
| [Employee{id=1}, Employee{id=2147483647}, Employee{id=-2147483648}]
|
排序就乱了。因为 Integer.MIN_VALUE - 1
变成了正数 2147483647
。
回到最开始的问题,正确的写法应该是
1 2 3 4 5 6 7 8 9
| class Employee implements Comparable { private int id;
@Override public int compareTo(Object o) { Employee emp = (Employee) o; return Integer.valueOf(this.id).compareTo(emp.id); } }
|
实际上,Integer.compareTo()
底层是通过调用Integer.compare()
方法实现的:
1 2 3 4 5 6 7 8
| public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }
|
所以上面的问题可以重写为
1 2 3 4 5 6 7 8 9
| class Employee implements Comparable { private int id;
@Override public int compareTo(Object o) { Employee emp = (Employee) o; return Integer.compare(this.id, emp.id); } }
|
值得注意的是,String
类型只有compareTo
方法,而没有compare
方法。给出源代码进行参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public int compareTo(String anotherString) { int len1 = value.length; int len2 = anotherString.value.length; int lim = Math.min(len1, len2); char v1[] = value; char v2[] = anotherString.value;
int k = 0; while (k < lim) { char c1 = v1[k]; char c2 = v2[k]; if (c1 != c2) { return c1 - c2; } k++; } return len1 - len2; }
|
可见String
类型不需要compare
方法。
基于这10道基础Java面试题,虐哭了多少人改写。
参考:
List集合排序Collections.sort()方法的一个容易忽略的小问题
原文链接: https://xqtony.github.io/2023/05/26/compareTo/
版权声明: 转载请注明出处.