比较器如何工作?

时间:2014-02-27 10:33:00

标签: java comparator autoboxing

我认为Collections.binarySearch()将返回永不返回0,因为比较器中的比较介于两个整数之间,==操作总是为假,但是运行结果让我失望......有人可以帮助我吗?

public class ObjectCompare {

    static Comparator<Integer> com = new Comparator<Integer>(){
        public int compare(Integer i, Integer j) {
            return i<j?-1:(i==j?0:1);// i thought i==j would never return true                                          
        }
    };

    public static void main(String[] args){
         String[] array = {"0","1","2","3","4","5"};
        List<Integer> list = new ArrayList<Integer>();
        Integer k = new Integer(1);
        Integer l = new Integer(1);
        System.out.println(k==l); // this return's false 
        for(String s : array)
            list.add(Integer.valueOf(s));
        System.out.println(Collections.binarySearch(list,1,com));// this returns 1
    }

}

5 个答案:

答案 0 :(得分:3)

如果我理解得很好,问题是“为什么binarySearch实际上在列表中找到了项目,当我的比较器比较实例时?”正确?

嗯,答案很简单:因为实际上它比较了两个相同的实例(引用)。 Integer类为-128和127(含)之间的值维护一个缓存实例池。当使用这些值之间的参数调用valueOf时,始终使用此实例池。

您的代码中有2次调用valueOf(1)(或多或少显式)。

一个在这里:list.add(Integer.valueOf(s));。对于循环的一次迭代,调用实际上是list.add(Integer.valueOf("1");在幕后,调用valueOf(int)

第二个是:Arrays.binarySearch(array,1,com)。从文字1Integer实例的装箱操作实际上是通过调用valueOf(int)来执行的。

答案 1 :(得分:2)

  

System.out.println(k==l);

这将返回false,因为它们是不同的对象。众所周知,您需要使用equals()方法来比较两个Integer对象的值。


  

return i<j?-1:(i==j?0:1);

这是compare()方法的return语句。 我不会等于j,除非列表中有两次相同的对象。请注意,compare()方法在内部由Collections.sort(list, comparator)方法调用。 binarySearch()方法不直接调用此方法。


  

System.out.println(Collections.binarySearch(list,1,com));

返回1,但此处的1表示搜索项找到的索引。如果您的搜索项为3,则会返回System.out.println(Collections.binarySearch(list,3,com));1返回的binarySearch()不是来自compare()方法。二进制搜索算法将在内部调用equals()方法,以在搜索期间比较Integer值。

因此,您认为永远不会满足的i == j中的compare()子句与在Integer列表上执行的实际二进制搜索无关。 / p>

来自Collections.binarySearch(List, searchItem, comparator)的文档:

  

使用二进制搜索算法在指定列表中搜索指定的对象。 在进行此调用之前,必须根据指定的比较器(通过sort(List,Comparator)方法)将列表按升序排序。

答案 2 :(得分:2)

使用此

System.out.println(k.equals(l)); // this return's true

而不是

System.out.println(k==l); // this return's false 

因为==这比较整数对象的地址而不是值...

 return i<j?-1:((i.equals(j))?0:1);// i thought i==j would return true 

而不是

return i<j?-1:((i==j)?0:1);// i thought i==j would never return true 

答案 3 :(得分:1)

Integerint的盒装变体,即引用类型。您需要使用Integer#equals方法来测试相等性,因为==只会测试引用是否相等:

static Comparator<Integer> com = new Comparator<Integer>(){
    public int compare(Integer i, Integer j) {
        return i < j ? -1 : (i.equals(j) ? 0 : 1);
    }
};

修改

现在我考虑一下,为Comparator编写Integer是没有意义的,因为Integer已经实现了Comparable<Integer>

答案 4 :(得分:1)

我冒昧地重新设计程序以专注于手头的问题:compare()方法中的i == j:

import java.util.Arrays;
import java.util.Comparator;

public class StackOverflow {

    static Comparator<Integer> com = new Comparator<Integer>(){
        @Override
        public int compare(Integer i, Integer j) {
          int res = 0;
          if(i<j){
            res = -1;
          } else if(i == j ){
            res = 0;
          } else {
            res = 1;
          }
          return res;
        }
    };

    public static void main(String[] args){
        Integer[] array = {0,1,2,3,4,5};
        System.out.println(Arrays.binarySearch(array,1,com));
    }
}

如果您调试/单步执行代码,您会看到在将1与1进行比较时,代码进入res = 0.这可能是一个自动装箱的怪癖?也许因为它必须为我自动取消装箱