我们需要一个 compareTo 方法,它与不同类的对象一起工作,并保证如果对象不相同,它将永远不会返回0。
Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2))
不能在Java中使用 System.identityHashCode 并不能保证两个不同的对象会返回不同的identityHashCode(是的,是的,它会发生)。
一些想法?
答案 0 :(得分:2)
由于不同的对象可以具有相同的System.identityHashCode()和hashCode(),所以无法确定该怎么做。你可以随意创建两个对象,对于这两个对象,使用Unsafe是相同的,如果你创建的则是随机的。
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的调试器执行此操作)
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());
}
}
这将确保所有不同类型的对象都是
Comparable
使用内置比较。toString()
进行比较,然后hashCode()
,然后System.identityHashCode
这意味着对于大多数对象,您将获得可预测的排序顺序。
注意:这将慢慢构建所有冲突对象的地图。它会很小,但却是内存泄漏的潜在来源。 WeakIdentityHashMap
会更好。