比较器和等号()

Sta*_*lin 11 java equals comparator treeset

假设我需要TreeSet使用某些域逻辑排序的元素.通过这个逻辑,一些元素的顺序并不重要,因此比较方法可以返回0,但在这种情况下我无法将它们放入TreeSet.

所以,问:我将从这样的代码中得到什么缺点:

class Foo implements Comparable<Foo>{}
new TreeSet<Foo>(new Comparator<Foo>(){
    @Override
    public int compare(Foo o1, Foo o2) {
        int res = o1.compareTo(o2);
        if(res == 0 || !o1.equals(o2)){
            return o1.hashCode() - o2.hashCode();
        }
        return res;
    }
});
Run Code Online (Sandbox Code Playgroud)

更新:

好.如果它应该永远是方法之间的一致性equals(),hashcode()并且compareTo(),作为@SPFloyd - seanizer和其他人说.如果它会更好,甚至是很好的,如果我将删除Comparable界面和移动这样的逻辑Comparator(我能做到这一点不破封装)?所以它将是:

class Foo{}
new TreeSet<Foo>(new Comparator<Foo>(){
    @Override
    public int compare(Foo o1, Foo o2) {
        //some logic start
        if(strictliBigger(o1, o2)){ return 1;}
        if(strictliBigger(o2, o1)){ return -1;}
        //some logic end
        if(res == 0 || !o1.equals(o2)){
            return o1.hashCode() - o2.hashCode();
        }
        return res;
    }
});
Run Code Online (Sandbox Code Playgroud)

更新2:

如果我不需要稳定排序会System.identityHashCode(x)更好hashCode()吗?

Sea*_*oyd 9

虽然这可能有效,但它远非最佳实践.

SortedSet文档:

请注意,如果有序集合要正确实现Set接口,则由有序集合维护的排序(无论是否提供显式比较器)必须与equals一致.(有关与equals一致的精确定义,请参阅Comparable接口或Comparator接口.)这是因为Set接口是根据equals操作定义的,但是有序集使用compareTo(或compare)方法执行所有元素比较因此,从排序集的角度来看,这种方法被认为相等的两个元素是相等的.即使排序与equals不一致,排序集的行为也是明确定义的; 它只是不遵守Set接口的一般合同.

对于实现的对象,Comparable方法之间应始终保持一致equals(),hashcode()并且compareTo().


我担心a SortedSet不是你想要的,番石榴MultiSet也不够(因为它不会让你独立检索多个相同的物品).我想你需要的是一个SortedList.我知道没有这样的野兽(也许在公共收藏中,但那些在传统方面有点),所以我使用Guava的ForwardingList作为基类为你实现了一个.简而言之:这个List几乎将所有内容委托给ArrayList它在内部使用,但是它使用Collections.binarySearch()它的add()方法来找到正确的插入位置,并且它抛出了UnsupportedOperationException在给定位置添加或设置值的ListListIterator接口的所有可选方法.

构造函数与那些构造函数相同ArrayList,但是对于每个构造函数,还有一个带有自定义的第二个版本Comparator.如果您不使用自定义Comparator,则需要实现列表元素,Comparable否则RuntimeException将在排序期间执行.

public class SortedArrayList<E> extends ForwardingList<E> implements
    RandomAccess{

    private final class ListIteratorImpl extends ForwardingListIterator<E>{
        private final int start;
        public ListIteratorImpl(final int start){
            this.start = start;
        }

        @Override
        public void set(E element){throw new UnsupportedOperationException();}

        @Override
        public void add(E element){throw new UnsupportedOperationException();}

        @Override
        protected ListIterator<E> delegate(){return inner.listIterator(start);};

    }

    private Comparator<? super E> comparator;

    private List<E> inner;

    public SortedArrayList(){this(null, null, null);}

    @SuppressWarnings("unchecked")
    private SortedArrayList(
        final List<E> existing,
        final Collection<? extends E> values,
        final Comparator<? super E> comparator
    ){
        this.comparator =
            (Comparator<? super E>)
               (comparator == null
                   ? Ordering.natural()
                   : comparator   );
        inner = (
            existing == null
                ? (values == null
                      ? new ArrayList<E>(values)
                      : new ArrayList<E>()
                   )
                : existing;
    }

    public SortedArrayList(final Collection<? extends E> c){
        this(null, c, null);
    }

    public SortedArrayList(final Collection<? extends E> c,
        final Comparator<? super E> comparator){
        this(null, c, comparator);
    }

    public SortedArrayList(final Comparator<? super E> comparator){
        this(null, null, comparator);
    }

    public SortedArrayList(final int initialCapacity){
        this(new ArrayList<E>(initialCapacity), null, null);
    }

    public SortedArrayList(final int initialCapacity,
        final Comparator<? super E> comparator){
        this(new ArrayList<E>(initialCapacity), null, comparator);
    }

    @Override
    public boolean add(final E e){
        inner.add(
            Math.abs(
                Collections.binarySearch(inner, e, comparator)
            ) + 1,
            e
        );
        return true;
    }

    @Override
    public void add(int i, E e){throw new UnsupportedOperationException();}

    @Override
    public boolean addAll(final Collection<? extends E> collection){
        return standardAddAll(collection);
    }

    @Override
    public boolean addAll(int i,
        Collection<? extends E> es){
        throw new UnsupportedOperationException();
    }

    @Override
    protected List<E> delegate(){ return inner; }

    @Override
    public List<E> subList(final int fromIndex, final int toIndex){
        return new SortedArrayList<E>(
            inner.subList(fromIndex, toIndex),
            null,
            comparator
        );
    }

    @Override
    public ListIterator<E> listIterator(){ return new ListIteratorImpl(0); }

    @Override
    public ListIterator<E> listIterator(final int index){
        return new ListIteratorImpl(index);
    }

    @Override
    public E set(int i, E e){ throw new UnsupportedOperationException(); }

}
Run Code Online (Sandbox Code Playgroud)