hashCode()
方法在java中返回什么值?如何在Java中计算hashCode()
我读到它是一个对象的内存引用...当我打印new Integer(1)
的散列值是1;对于String("a")
是97.
我很困惑:它是ASCII还是什么类型的值?
hashCode()
方法在java中返回什么值?如何在Java中计算hashCode()
我读到它是一个对象的内存引用...当我打印new Integer(1)
的散列值是1;对于String("a")
是97.
我很困惑:它是ASCII还是什么类型的值?
哈希码是一个整数值,它表示被调用的对象的状态。这就是为什么设置为1的Integer
将返回“1”的哈希码,因为Integer's
哈希码及其值是相同的东西。一个字符的哈希码等于它的ASCII字符码。如果您编写自定义类型,则需要负责创建一个能够最好地表示当前实例状态的好实现。
hashCode()
返回的值不能保证是对象的内存地址。我不确定Object
类中的实现,但请记住,大多数类将覆盖hashCode()
,使得两个语义等价(但不是相同实例)的实例将哈希到相同的值。如果这些类可以在另一个数据结构(例如Set)中使用,这依赖于与equals
一致的hashCode
,这一点尤其重要。
没有hashCode()
唯一标识一个对象的实例,不管是什么。如果你想要一个基于底层指针的hashcode(例如在Sun的实现中),使用System.identityHashCode()
- 这将委托给默认的hashCode
方法,而不管它是否被覆盖。
尽管如此,即使System.identityHashCode()
可以为多个对象返回相同的散列。请参阅注释以获得解释,但这里是一个示例程序,它持续生成对象,直到它找到两个具有相同的System.identityHashCode()
。当我运行它时,它很快找到两个匹配的平均值,在将大约86,000个Long包装器对象(以及该键的整数包装器)添加到地图后平均匹配。
public static void main(String[] args) {
Map<Integer,Long> map = new HashMap<>();
Random generator = new Random();
Collection<Integer> counts = new LinkedList<>();
Long object = generator.nextLong();
// We use the identityHashCode as the key into the map
// This makes it easier to check if any other objects
// have the same key.
int hash = System.identityHashCode(object);
while (!map.containsKey(hash)) {
map.put(hash, object);
object = generator.nextLong();
hash = System.identityHashCode(object);
}
System.out.println("Identical maps for size: " + map.size());
System.out.println("First object value: " + object);
System.out.println("Second object value: " + map.get(hash));
System.out.println("First object identityHash: " + System.identityHashCode(object));
System.out.println("Second object identityHash: " + System.identityHashCode(map.get(hash)));
}
输出示例:
Identical maps for size: 105822
First object value: 7446391633043190962
Second object value: -8143651927768852586
First object identityHash: 2134400190
Second object identityHash: 2134400190
的hashCode()
方法通常用于识别一个对象。我认为Object
实现返回对象的指针(不是一个真正的指针,而是一个唯一的ID或类似的东西)。但大多数类都会覆盖该方法。类似String
类。两个String对象有不一样的指针,但他们是平等的:
new String("a").hashCode() == new String("a").hashCode()
我认为hashCode()
最常见的用途是在Hashtable
,HashSet
等。
编辑: (由于最近的downvote和基于我阅读的关于JVM参数的文章)
随着JVM参数-XX:hashCode
您可以更改hashCode的计算方式(请参阅Java专家通讯的Issue 222)。
HashCode == 0:只是返回随机数字,与内存中找不到的 无关。据我所知,种子的全局读写对于有很多处理器的系统来说并不是最佳的。
HashCode == 1:计算哈希代码值,不确定它们在什么值 开始,但它似乎相当高。
HashCode == 2:始终返回完全相同的标识哈希码1. 这可用于测试依赖于对象标识的代码。 原因为什么JavaChampionTest在上面的示例 中返回Kirk的URL的原因是所有对象都返回相同的哈希码。
HashCode == 3:从零开始计算哈希码值。它 看起来不是线程安全的,因此多个线程可以生成具有相同哈希代码的对象 。
HashCode == 4:这似乎与创建对象的内存位置 有一些关系。
HashCode> = 5:这是Java 8的默认算法,每个线程种子有一个 。它使用Marsaglia的xor-shift方案来生成 伪随机数。
如果我正确阅读代码,则在Java 8和9中,默认策略为5. – 2017-09-01 22:56:34
如果内存正常工作(检查JavaDoc是否为java.lang.Object),则取决于实现,Object.hashCode()将根据对象而变化(Sun JVM从该值派生值对该对象的引用)。请注意,如果您正在实现任何非平凡对象,并且想要将它们正确存储在HashMap或HashSet中,则必须重写hashCode()和equals()。 hashCode()可以做任何你喜欢的事情(这是完全合法的,但让它返回1是不理想的),但重要的是如果你的equals()方法返回true,那么hashCode()返回的值对于两个对象是相等的。
混乱和缺乏对hashCode()和equals()的理解是错误的重要来源。确保你完全熟悉Object.hashCode()和Object.equals()的JavaDocs,并且我保证花费的时间会为自己付出代价。
我看,这是一个对象的内存引用..
号Object.hashCode()
用于大约14年前返回一个内存地址。从此以后。
什么类型的值是
它是什么完全取决于你在说什么类,它是否已经覆盖`是Object.hashCode()。
这不提供问题的答案。要批评或要求作者澄清,请在其帖子下方留言。 – 2015-05-24 13:59:43
@chsdk垃圾。它驳斥了这个问题中的一个断言。 '不'是答案。注意我也没有要求任何人澄清。 – EJP 2016-08-04 12:18:25
这是一个自动评论,在一个标志为“不是答案”之后,在你最后一次编辑前2小时之前,这个答案还不清楚,并且无法解释。 – 2016-08-04 15:05:00
如果你想知道它们是如何被破坏的,我建议你阅读源代码。如果您使用的是IDE,您可以只使用您感兴趣的方法,并查看方法的实现方式。如果你不能这样做,你可以谷歌的来源。
例如,Integer。hashCode()方法被实现为
public int hashCode() {
return value;
}
和String.hashCode()
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
我已经计划以完全相同的方式回答; +1 – incarnate 2010-03-13 07:05:56
@Peter Lawrey以及我如何看到Object hashCode的实现 – 2013-10-07 09:43:15
@naroji它在OpenJDK中。不幸的是,有多种策略,不清楚使用哪一种。 – 2013-10-07 13:39:14
public static int murmur3_32(int paramInt1, char[] paramArrayOfChar, int paramInt2, int paramInt3) {
/* 121 */ int i = paramInt1;
/* */
/* 123 */ int j = paramInt2;
/* 124 */ int k = paramInt3;
/* */
/* */ int m;
/* 127 */ while (k >= 2) {
/* 128 */ m = paramArrayOfChar[(j++)] & 0xFFFF | paramArrayOfChar[(j++)] << '\020';
/* */
/* 130 */ k -= 2;
/* */
/* 132 */ m *= -862048943;
/* 133 */ m = Integer.rotateLeft(m, 15);
/* 134 */ m *= 461845907;
/* */
/* 136 */ i ^= m;
/* 137 */ i = Integer.rotateLeft(i, 13);
/* 138 */ i = i * 5 + -430675100;
/* */ }
/* */
/* */
/* */
/* 143 */ if (k > 0) {
/* 144 */ m = paramArrayOfChar[j];
/* */
/* 146 */ m *= -862048943;
/* 147 */ m = Integer.rotateLeft(m, 15);
/* 148 */ m *= 461845907;
/* 149 */ i ^= m;
/* */ }
/* */
/* */
/* */
/* 154 */ i ^= paramInt3 * 2;
/* */
/* */
/* 157 */ i ^= i >>> 16;
/* 158 */ i *= -2048144789;
/* 159 */ i ^= i >>> 13;
/* 160 */ i *= -1028477387;
/* 161 */ i ^= i >>> 16;
/* */
/* 163 */ return i;
/* */ }
如果你真的很想学习然后再通过Hashing.class可用此代码;
这里第一个参数HASHING_SEED是基于下面的代码
{
long nanos = System.nanoTime();
long now = System.currentTimeMillis();
int SEED_MATERIAL[] = {
System.identityHashCode(String.class),
System.identityHashCode(System.class),
(int) (nanos >>> 32),
(int) nanos,
(int) (now >>> 32),
(int) now,
(int) (System.nanoTime() >>> 2)
};
// Use murmur3 to scramble the seeding material.
// Inline implementation to avoid loading classes
int h1 = 0;
// body
for (int k1 : SEED_MATERIAL) {
k1 *= 0xcc9e2d51;
k1 = (k1 << 15) | (k1 >>> 17);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
h1 = h1 * 5 + 0xe6546b64;
}
// tail (always empty, as body is always 32-bit chunks)
// finalization
h1 ^= SEED_MATERIAL.length * 4;
// finalization mix force all bits of a hash block to avalanche
h1 ^= h1 >>> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >>> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >>> 16;
HASHING_SEED = h1;
}
所述第二参数是字符串的字符数组计算,第三个是总是“0”和第四个是char数组长度。
而上述计算仅适用于String哈希码。
对于所有整数,其散列码将是其整数值。 对于字符(最多两个字母)它将是ASCII码。
我不知道这段代码来自哪里,但它与Java的'String :: hashCode()'计算方式无关。或者其他任何标准的Java类型的哈希码...... AFAIK。 String :: hashCode()的* real *代码在这里:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/String的.java#String.hashCode%28%29 – 2017-09-01 22:30:02
尽管合理实用,但Object类定义的hashCode方法确实会为不同的对象返回不同的整数。 (这一般是通过将该对象的内部地址转换成一个整数来实现的,但不是由Java™编程语言不需要这种实现技巧。)
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
这被改装成下跌有什么特别的原因吗?如果这里有什么不正确的话,我会喜欢一个更正,但是如果没有解释就会失望,这对讨论没有任何帮助。 – danben 2010-03-11 20:09:38
几年前,Ted Neward在http://blogs.tedneward.com/2008/07/16/ObjecthashCode+Implementation.aspx中解释了OpenJDK如何实现Object.hashCode()。 OpenJDK从对象地址派生散列码,但缓存该值并将其返回给后续调用者,以防对象在内存中移动并改变其地址。 在简要回顾了最新的代码之后,我发现自从Neward写他的文章以来,实现似乎没有改变。 – 2010-04-27 17:35:57
这似乎支持我的答案。 – danben 2010-04-27 20:27:09