Java:实现比较接口时,应该全面的进行各种情况的比较

Java中实现类的自定义比较功能,可以通过实现Comparable,或者Comparator,前者是一个内比较器,后者是一个外比较器,但无论是哪种在实现比较方法时,都应该充分考虑各种情况:

  1. 比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数
  2. 比较者等于被比较者,那么返回0
  3. 比较者小于被比较者,那么返回负整数

假如只考虑了其中的两种情况,会有什么影响了?

Bad Case
考虑下面的实现,在调用TreeSet或者TreeMap的containsKey时会有什么影响了?

@Data
@EqualsAndHashCode
class ImgSize implements Comparable {
    private int width;
    private int height;

    public ImgSize(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public int compareTo(ImgSize obj) {
        if (this.width < obj.width) {
            return -1;
        } else if (this.height < obj.height) {
            return -1;
        }  else {
            return 1;
        }
    }
}
Map pics = new TreeMap<>();
        pics.put(new ImgSize(3,4), "Pic_A");
        pics.put(new ImgSize(1,3), "Pic_B");
        pics.put(new ImgSize(1,2), "Pic_C");
        for(Map.Entry entry:pics.entrySet()) {
            System.out.println(entry);
        }

        System.out.println(pics.containsKey(new ImgSize(1,2)));
// 输出
ImgSize(width=1, height=2)=Pic_C
ImgSize(width=1, height=3)=Pic_B
ImgSize(width=3, height=4)=Pic_A
false

尽管实现了排序功能,但是containsKey方法返回的false,这是为何了?不妨看下它的实现

public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }
final Entry getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable k = (Comparable) key;
        Entry p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }

本以为containsKey是根据hashCode和equals方法来实现的,已lombok注解已经实现了这两个方法,然而containsKey实际是根据比较器实现的,如果自定义的比较器中没有相等的实现,containsKey是不会正确返回预期的结果的。

修正

@Data
@EqualsAndHashCode
class ImgSize implements Comparable {
    private int width;
    private int height;

    public ImgSize(int width, int height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public int compareTo(ImgSize obj) {
        if (this.width < obj.width) {
            return -1;
        } else if (this.width == obj.width) {
            return (this.height < obj.height ? -1:(this.height == obj.height ? 0 : 1));
        } else {
            return 1;
        }
    }
}

你可能感兴趣的:(JAVA)