考虑一个具有可比较的(与equals一致)和一个不可比较的字段(该类我不知道它是否覆盖Object#equals)的类。

应该比较类的实例,其中结果的顺序应与等号一致,即,如果两个字段都相等(根据0)并且与可比较字段的顺序一致,则返回Object#equals。我使用System.identityHashCode覆盖了这些要求未涵盖的大多数情况(具有相同可比性,但其他值不同的实例的顺序是任意的),但是不确定这是否是最佳方法。

public class MyClass implements Comparable<MyClass> {
    private Integer intField;
    private Object nonCompField;

    public int compareTo(MyClass other) {
        int intFieldComp = this.intField.compareTo(other.intField);
        if (intFieldComp != 0)
            return intFieldComp;
        if (this.nonCompField.equals(other.nonCompField))
            return 0;
        // ...and now? My current approach:
        if (Systems.identityHashCode(this.nonCompField) < Systems.identityHashCode(other.nonCompField))
            return -1;
        else
            return 1;
     }
}


我在这里看到两个问题:


如果两个对象的Systems.identityHashCode相同,则每个大于另一个。 (这会发生吗?)
就我理解intField的作用而言,具有相同nonCompField值和不同Systems.identityHashCode值的实例的顺序在程序运行之间不必保持一致。


那是对的吗?还有更多问题吗?最重要的是,有没有解决的办法?

最佳答案

Systems.identityHashCode […]对于两个对象[…]相同(这会发生吗?)


是的,它可以。引用Java API Documentation


  在合理可行的范围内,由类hashCode定义的Object方法确实为不同的对象返回不同的整数。
  identityHashCode(Object x)为给定对象返回与默认方法hashCode()返回的哈希码相同的哈希码,无论给定对象的类是否覆盖hashCode()


因此,您可能会遇到哈希冲突,并且随着内存的增长,但是哈希码固定为32位,它们的可能性会越来越大。


  就我理解intField的作用而言,具有相同nonCompField值和不同Systems.identityHashCode值的实例的顺序在程序运行之间不必保持一致。


对。在同一程序的单次调用期间,它甚至可能有所不同:即使(1,foo) < (1,bar) < (1,baz),您也可能具有foo.equals(baz)


  最重要的是,有没有解决的办法?


您可以维护一个映射,该映射将不可比较类型的每个不同值映射到您为遇到的每个不同值增加的序列号。

但是,内存管理将非常棘手:您不能使用WeakHashMap,因为代码可能会使您的关键对象无法访问,但仍保留对具有相同值的另一个对象的引用。因此,要么维护对给定值的所有对象的弱引用列表,要么简单地使用强引用并接受一个事实,即遇到的任何不可比的值将永远不会被垃圾回收。

请注意,除非您以相同的顺序可重复创建值,否则该方案仍不会产生可重复的序列号。

关于java - compareTo涉及不可比领域:如何保持可传递性?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12515057/

10-10 08:21