本文共 2550 字,大约阅读时间需要 8 分钟。
Java中实现类的自定义比较功能,可以通过实现Comparable,或者Comparator,前者是一个内比较器,后者是一个外比较器,但无论是哪种在实现比较方法时,都应该充分考虑各种情况:
假如只考虑了其中的两种情况,会有什么影响了?
Bad Case
考虑下面的实现,在调用TreeSet或者TreeMap的containsKey时会有什么影响了?@Data@EqualsAndHashCodeclass 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; } }}
Mappics = 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_CImgSize(width=1, height=3)=Pic_BImgSize(width=3, height=4)=Pic_Afalse
尽管实现了排序功能,但是containsKey方法返回的false,这是为何了?不妨看下它的实现
public boolean containsKey(Object key) { return getEntry(key) != null; }final EntrygetEntry(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@EqualsAndHashCodeclass 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; } }}
转载地址:http://skbmb.baihongyu.com/