如何编写比较器的equals()

时间:2016-08-09 19:45:22

标签: java comparator

我正在尝试实现Comparator的equals方法,但是中途停留。 关于equals()中的描述" sgn(comp1.compare(o1,o2))== sgn(comp2.compare(o1,o2))对于每个对象引用o1和o2。"我应该采用这种方法吗?当我写equals()时,如何知道每个对象引用o1和o2。

      Comparator c = new Comparator<Interval>() {
        @Override
        public int compare(Interval o1, Interval o2) {
            return o1.start - o2.start;
        }

        @Override
        public boolean equals(Object obj) {
            Type genericType = obj.getClass().getGenericInterfaces()[0];
            Type type = ((ParameterizedType) genericType).getActualTypeArguments()[0];
            if (((Class<?>) type).getName().equals(Interval.class.getName())) {
                // how to implement
                // "sgn(comp1.compare(o1,o2))==sgn(comp2.compare(o1, o2))
                // for every object reference o1 and o2."
                return true;
            }
            return false;
        }
    };

1 个答案:

答案 0 :(得分:1)

如果比较器以相同的方式对元素进行排序,则可以认为它们是等效的。这个测试可以用于优化排序,但实际上我并不知道核心Java集合利用了这个提示。

未能认识到这种等价可能会消除一些优化的理论机会,但它不会破坏任何东西。因此,通常没有必要覆盖equals()方法。

正如Comparator.equals()的文档所说:

  

请注意总是安全而非才能覆盖Object.equals(Object)

如果您可以将订单定义为类或实例成员,而不是每次使用时都创建新实例,则equals()的默认基于身份的实现很有效。这样,可以检测到使用相同比较器的两个已排序集合,因为它们的比较器将是相等的。

private static final Comparator<Interval> orderByStart = new Comparator<Interval>() {
  @Override
  public int compare(Interval o1, Interval o2) {
    return o1.start - o2.start;
  }    
};
  

我认为这是一个解决方法

没有。这是实现Comparator.equals()方法的正确方法。

让我们仔细看看你坚持的解决方案:

Comparator<Interval> c = new Comparator<Interval>() {

  @Override
  public int compare(Interval o1, Interval o2) {
    return o1.start - o2.start;
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof Comparator<?>))
      return false;
    @SuppressWarnings("unchecked") /* We'll catch this below. */
    Comparator<Interval> that = (Comparator<Interval>) obj;
    return 
       IntStream.rangeClosed(Integer.MIN_VALUE, Integer.MAX_VALUE)
      .mapToObj(Interval::new)
      .allMatch(o1 -> {
         return
            IntStream.rangeClosed(Integer.MIN_VALUE, Integer.MAX_VALUE)
           .mapToObj(Interval::new)
           .allMatch(o2 -> {
              int sig = Integer.signum(compare(o1, o2));
              try {
                return Integer.signum(that.compare(o1, o2)) == sig;
              } catch (ClassCastException ex) {
                return false;
              }
            });
       });
  }

};

equals()的{​​{1}}方法意味着优化。如果您无法快速有效地测试平等,请不要费心 - “总是安全”。相反的是 not true:正如我在此处演示的那样,错误地实施Comparator存在危险。

如果你不能使用正确的习语,你的程序看起来很糟糕,表现更差。