在Java中排序对象,不带';适当的';比较法
我们需要一个compareTo方法,该方法可以处理不同类的对象,并保证如果对象不相同,它永远不会返回0在Java中排序对象,不带';适当的';比较法,java,Java,我们需要一个compareTo方法,该方法可以处理不同类的对象,并保证如果对象不相同,它永远不会返回0 Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2)) 在Java中不起作用并不保证两个不同的对象将返回不同的identityHashCode(是的,是的) 一些想法?由于不同的对象可以同时具有相同的System.identityHashCode()和hashCode(),因此不确定该怎么做。可以使
Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2))
在Java中不起作用并不保证两个不同的对象将返回不同的identityHashCode(是的,是的)
一些想法?由于不同的对象可以同时具有相同的System.identityHashCode()和hashCode(),因此不确定该怎么做。可以使用“不安全”随意创建两个对象,如果创建的对象足够多,则可以随机创建两个对象
public class UnsafeIdentityDemo {
static final Unsafe UNSAFE;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
public static void setIdentityHashCode(Object o, int code) {
UNSAFE.putInt(o, 1l, code & 0x7FFF_FFF);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Double d = 1.0;
Double d2 = 1.0;
setIdentityHashCode(d, 1);
setIdentityHashCode(d2, 1);
System.out.println("d: "+d+" System.identityHashCode(d): "+System.identityHashCode(d));
System.out.println("d2: "+d2+" System.identityHashCode(d2): "+System.identityHashCode(d2));
System.out.println("d == d2: " + (d == d2));
}
}
印刷品
d: 1.0 System.identityHashCode(d): 1
d2: 1.0 System.identityHashCode(d2): 1
d == d2: false
您可以做的是根据对象被发现的顺序分配对象(IntelliJ的调试器会这样做)
公共类UniversalComparator实现Comparator{
@凌驾
公共整数比较(对象o1、对象o2){
如果(o1==o2)
返回0;
int cmp=compare(o1.getClass(),o2.getClass());
//如果类别相同,且具有可比性。
if(cmp==0&&o1可比实例)
cmp=((可比)o1)。与(o2)相比;
//否则,请使用内置的toString/hashCode/identityHashCode
如果(cmp==0)
cmp=Integer.compare(o1.toString(),o2.toString());
如果(cmp==0)
cmp=Integer.compare(o1.hashCode(),o2.hashCode());
如果(cmp==0)
cmp=整数。比较(System.identityHashCode(o1)、System.identityHashCode(o2));
//否则,为它们生成唯一的id
如果(cmp==0)
cmp=整数。比较(uniqueId(o1),uniqueId(o2));
返回cmp;
}
最终映射uniqueId=新标识hashmap();
专用同步整数唯一ID(对象o){
返回uniqueId.computeIfAbsent(o,k->uniqueId.size());
}
}
这将确保所有不同类型的对象
- 首先按类名排序
- 如果同一类且
则使用内置的比较可比
- 否则,如果是同一类,则通过比较
,然后比较toString()
,然后比较hashCode()
System.identityHashCode
- 否则,生成一个唯一的id
注意:这将慢慢建立所有冲突对象的映射。它将很小,但可能是内存泄漏的一个来源。一个
WeakIdentityHashMap
会更好。这里的不一样到底意味着什么?你不能用==
检查引用吗?如果类完全不同,你如何知道一个对象比另一个对象大?不同类的对象?请解释一下:这是否意味着o1
和o2
在对compareTo
的同一调用中可能属于不同的类?您需要使用compareTo对它们进行排序,还是说它们是否相同/不同?您不能为随机对象提供对称规则。@Thomas System.identityHashCode(o1)是随机生成的,因此在64K对象的集合中,它们发生冲突的可能性很高。在获取唯一id之前,还可以使用类的哈希代码来降低冲突的概率。这将进一步降低内存泄漏的风险。只是澄清一下:我不是指o1.hashCode()
(这可能也有帮助)而是o1.getClass().hashCode()
,因为对象可能是OP声明的不同类。@Thomas你可以,尽管我会比较类名。嗯,这有什么好处?更好定义的散列码?@Thomas您的建议让我了解了如何使大多数对象的排序顺序可预测。
public class UniversalComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
if (o1 == o2)
return 0;
int cmp = compare(o1.getClass(), o2.getClass());
// if the classes are the same, and they are Comparable.
if (cmp == 0 && o1 instanceof Comparable)
cmp = ((Comparable) o1).compareTo(o2);
// otherwise use the built in toString/hashCode/identityHashCode
if (cmp == 0)
cmp = Integer.compare(o1.toString(), o2.toString());
if (cmp == 0)
cmp = Integer.compare(o1.hashCode(), o2.hashCode());
if (cmp == 0)
cmp = Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2));
// otherwise generate a unique id for them
if (cmp == 0)
cmp = Integer.compare(uniqueId(o1), uniqueId(o2));
return cmp;
}
final Map<Object, Integer> uniqueId = new IdentityHashMap<>();
private synchronized int uniqueId(Object o) {
return uniqueId.computeIfAbsent(o, k -> uniqueId.size());
}
}