【发布时间】:2015-07-23 06:27:30
【问题描述】:
什么时候使用 System.identityhashcode() 和 hashcode() 方法?*
【问题讨论】:
什么时候使用 System.identityhashcode() 和 hashcode() 方法?*
【问题讨论】:
根据 javadoc,System.identityHashCode(Object o):
无论给定对象的类是否覆盖 hashCode(),返回给定对象的哈希码与默认方法 hashCode() 返回的哈希码相同。空引用的哈希码为零。
因此,首先,System.identityHashCode(nullReference) 将始终为您提供0,而不是nullReference.hashCode(),后者显然会在运行时为您提供NullPointerException。
但是,让我们考虑以下类:
public class MysteriousOne {
@Override
public int hashCode() {
return 0xAAAABBBB;
}
//override equals() and so on...
}
该类覆盖hashCode(),这非常好,即使每个实例的哈希码都相同,但是如果您想区分多个实例的身份,这并不好。通常,您会尝试.toString() 方法的输出(默认情况下给出类名,然后是@,然后是hashCode() 输出),例如,找出对象的真实身份,但在这种情况下,输出将是相同的:
MysteriousOne first = new MysteriousOne();
MysteriousOne second = new MysteriousOne();
System.out.println("First: " + first);
System.out.println("Second: " + second);
输出将是:
First: MysteriousOne@aaaabbbb
Second: MysteriousOne@aaaabbbb
因此,拥有hashCode() 这样的实现是不可能区分多个实例的身份的。这就是System.identityHashCode() 派上用场的地方。
如果你这样做
System.out.println("First: " + System.identityHashCode(first));
System.out.println("Second: " + System.identityHashCode(second));
即使他们的类实现的hashCode() 返回一个常量,对于不同的实例,您也会得到两个不同的数字(实际上,这里根本不会调用hashCode() 的覆盖实现,根据javadoc):
First: 366712642
Second: 1829164700
此外,您甚至可以将原语传递给System.identityHashCode(Object o),因为它们将被装箱到相应的包装器中:
int i = 5;
System.out.println(System.identityHashCode(i));
更多信息:
【讨论】:
identityHashCode,hashCode() 的作者应该修复了这个函数:),每个对象都有相同的常量 hashCode instance 似乎是该方法的不正确实现。对于identityHashCode,这似乎不是一个好的用例。
System.identityHashCode() 时,覆盖的 hashCode() 实现将不会到位。
public static int identityHashCode(Object x)
无论给定对象的类是否覆盖 hashCode(),返回给定对象的哈希码与默认方法 hashCode() 返回的哈希码相同。空引用的哈希码为零。
请注意,identityHashCode 返回 hashCode 与 Object 类中实现的一样,这不是您通常想要的,因此您应该使用 yourObject.hashCode()。
关于此方法是否有一些用例,如果您有一个 Objects 数组,您正在迭代其中可能有一些 null,并且您需要这些对象的 hashCode,使用System.identityHashCode(obj) 可以为您节省一次空检查,并没有那么大的改进。
【讨论】:
您的某些类可能会覆盖系统中的hashcode() 方法。对于这些对象,此方法提供所提供对象的哈希码,该哈希码将从其最终父级java.lang.Object 返回。请参阅Java API 以查看语言设计者的描述。
我相信它的用途是当您出于某些原因想要创建几乎不唯一的对象时。当我说几乎时,可能会有具有相同哈希码的对象。这样做实际上会尽量减少 equals 方法的使用。
【讨论】:
System.identityhashcode() 始终返回默认的 java.lang.Object 实现,即使特定对象的类覆盖此实现并计算不同的哈希码。
在某些情况下,您可能需要这样的定义:当且仅当 o1 == o2 时,两个对象 o1 和 o2 才被认为相等。在正常实现中,两个对象 o1 和 o2 被认为是相等的,当且仅当 o1 == null ? o2 == null:o1.equals(o2)。 如果两个对象相等当且仅当 o1 == o2 时,它们必须具有相同的哈希码。所以你应该使用 System.identityhashcode()。
这是我遇到的一些代码 sn-ps。
private static int hash(Object x, int length) {
int h = System.identityHashCode(x);
// Multiply by -127, and left-shift to use least bit as part of hash
return ((h << 1) - (h << 8)) & (length - 1);
}
IdentityHashMap.java
public int hashCode() {
return System.identityHashCode(instance);
}
@Override
@SuppressWarnings("rawtypes")
public boolean equals(final Object other) {
return other instanceof IdentityWrapper &&
((IdentityWrapper) other).instance == instance;
}
IdentityWrapper.java(来自 Apache Commons Pool 2)
【讨论】:
好吧,对于初学者来说,虽然 System 当然有一个 hashCode() 方法(每个 Object 都有一个),但我认为没有太多理由调用它。或者甚至有机会获得一个 System object 来调用它,因为 System 是 final 而构造函数是 private。所以,我猜hashCode() 可能“几乎永远不会”。
所以,这给我们留下了System.identityHashCode(Object),它为您提供了任何对象的简单的默认哈希码值。所以,换句话说,你并不经常需要它,因为如果你不在你的类中重写 hashCode() 方法,你将默认为你的对象获得相同的返回值(因为实际上默认的 hashCode (),当你没有重写 hashCode() 方法时,就是System.identityHashCode(this))。可能有一些用例何时使用它,但它们非常罕见。
【讨论】: