62

hashCode()该方法在java中返回什么值?

我读到它是一个对象的内存引用......哈希值为new Integer(1)1;的哈希值为String("a")97。

我很困惑:它是 ASCII 还是什么类型的值?

4

10 回答 10

53

不保证返回的值hashCode()是对象的内存地址。我不确定Object类中的实现,但请记住,大多数类将覆盖hashCode(),使得语义上等价的两个实例(但不是同一个实例)将散列到相同的值。如果类可以在依赖于hashCodeequals.

无论如何,都没有hashCode()唯一标识对象的实例。如果您想要一个基于底层指针的哈希码(例如在 Sun 的实现中),请使用System.identityHashCode()- 这将委托给默认hashCode方法,无论它是否已被覆盖。

尽管如此,甚至System.identityHashCode()可以为多个对象返回相同的哈希值。请参阅注释以获取解释,但这里有一个示例程序,它不断生成对象,直到找到两个具有相同的System.identityHashCode(). 当我运行它时,它会快速找到两个System.identityHashCode()匹配的 s,平均在将大约 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
于 2010-03-11T18:35:51.553 回答
51

哈希码是一个整数值,表示调用它的对象的状态。这就是为什么Integer设置为 1 将返回哈希码“1”的原因,因为Integer's哈希码和它的值是相同的。一个字符的哈希码等于它的 ASCII 字符码。如果您编写自定义类型,您有责任创建一个hashCode能够最好地代表当前实例状态的良好实现。

于 2010-03-11T18:33:37.453 回答
24

如果您想知道它们是如何实现的,我建议您阅读源代码。如果您使用的是 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;
   }
于 2010-03-13T06:49:20.787 回答
8

hashCode()方法通常用于识别对象。我认为Object实现返回对象的指针(不是真正的指针,而是唯一的 id 或类似的东西)。但是大多数类会覆盖该方法。喜欢String上课。两个 String 对象的指针不同但它们相等:

new String("a").hashCode() == new String("a").hashCode()

我认为 for 最常见的用途hashCode()是 in Hashtable,HashSet等。

Java API 对象 hashCode()

编辑:(由于最近的反对票和基于我读到的一篇关于 JVM 参数的文章)

使用 JVM 参数-XX:hashCode,您可以更改计算 hashCode 的方式(请参阅Java 专家时事通讯的第 222期)。

HashCode==0:只返回随机数,与对象在内存中的位置无关。据我所知,种子的全局读写对于具有大量处理器的系统并不是最佳的。

HashCode==1:对哈希码值进行计数,不确定它们从什么值开始,但似乎相当高。

HashCode==2:始终返回完全相同的身份哈希码 1。这可用于测试依赖于对象身份的代码。JavaChampionTest 在上面的示例中返回 Kirk 的 URL 的原因是所有对象都返回相同的哈希码。

HashCode==3:从零开始计数哈希码值。它看起来不是线程安全的,因此多个线程可以生成具有相同哈希码的对象。

HashCode==4:这似乎与创建对象的内存位置有关。

HashCode>=5:这是 Java 8 的默认算法,具有每个线程的种子。它使用 Marsaglia 的异或移位方案来产生伪随机数。

于 2010-03-11T18:48:08.240 回答
6

我读到它是一个对象的内存引用..

No.Object.hashCode()用于返回大约 14 年前的内存地址。从此没有。

什么类型的值是

它是什么完全取决于你在谈论什么类以及它是否覆盖了`Object.hashCode()。

于 2010-03-13T01:26:51.787 回答
3

定义: String hashCode() 方法以整数形式返回 String 的 hashcode 值。

语法: public int hashCode()

哈希码使用以下公式计算

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

where:

s is ith character in the string
n is length of the string
^ is exponential operand

示例: 例如,如果您想计算字符串“abc”的哈希码,那么我们有以下详细信息

s[] = {'a', 'b', 'c'}
n = 3

因此哈希码值将计算为:

s[0]*31^(2) + s[1]*31^1 + s[2]
= a*31^2 + b*31^1 + c*31^0
= (ASCII value of a = 97, b = 98 and c = 99)
= 97*961 + 98*31 + 99 
= 93217 + 3038 + 99
= 96354

所以' abc '的哈希码值为96354

于 2021-02-09T20:41:44.190 回答
3

来自 OpenJDK 源代码(JDK8):

使用默认值 5 生成哈希码:

product(intx, hashCode, 5,                                                
      "(Unstable) select hashCode generation algorithm")       

一些常量数据和随机生成的数字,每个线程启动一个种子:

// thread-specific hashCode stream generator state - Marsaglia shift-xor form
  _hashStateX = os::random() ;
  _hashStateY = 842502087 ;
  _hashStateZ = 0x8767 ;    // (int)(3579807591LL & 0xffff) ;
  _hashStateW = 273326509 ;

然后,此函数创建 hashCode(默认为 5,如上所述):

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     // This form uses an unguarded global Park-Miller RNG,
     // so it's possible for two threads to race and generate the same RNG.
     // On MP system we'll have lots of RW access to a global, so the
     // mechanism induces lots of coherency traffic.
     value = os::random() ;
  } else
  if (hashCode == 1) {
     // This variation has the property of being stable (idempotent)
     // between STW operations.  This can be useful in some of the 1-0
     // synchronization schemes.
     intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else
  if (hashCode == 2) {
     value = 1 ;            // for sensitivity testing
  } else
  if (hashCode == 3) {
     value = ++GVars.hcSequence ;
  } else
  if (hashCode == 4) {
     value = cast_from_oop<intptr_t>(obj) ;
  } else {
     // Marsaglia's xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we'll
     // likely make this the default in future releases.
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;
  }

  value &= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ;
  assert (value != markOopDesc::no_hash, "invariant") ;
  TEVENT (hashCode: GENERATE) ;
  return value;
}

因此我们可以看到,至少在 JDK8 中,默认设置为特定于随机线程。

于 2018-09-26T12:04:40.927 回答
2

Object.hashCode(),如果内存服务正确(检查 java.lang.Object 的 JavaDoc),是依赖于实现的,并且会根据对象而改变(Sun JVM 从对对象的引用的值中派生值)。

请注意,如果您正在实现任何重要的对象,并希望将它们正确存储在 HashMap 或 HashSet 中,则必须覆盖 hashCode() 和 equals()。hashCode() 可以做任何你喜欢的事情(它完全合法,但让它返回 1 不是最理想的。),但如果你的 equals() 方法返回 true,那么 hashCode() 为两个对象返回的值是相等的,这一点很重要。

对 hashCode() 和 equals() 的混淆和缺乏理解是 bug 的一大来源。确保您完全熟悉 Object.hashCode() 和 Object.equals() 的 JavaDocs,我保证所花费的时间会收回成本。

于 2010-03-11T18:54:12.563 回答
0

我很惊讶没有人提到这一点,但是尽管对于任何非Object类来说很明显,你的第一个动作应该是阅读许多类的源代码,.hashcode()Object这种情况下,根据你的 JVM,可能会发生一些不同的有趣的事情执行。Object.hashcode()调用System.identityHashcode(object).

确实在内存中使用对象地址是古老的历史,但许多人没有意识到他们可以控制这种行为以及如何Object.hashcode()通过 jvm 参数计算-XX:hashCode=N其中 N 可以是 [0-5] 中的数字...

0 – Park-Miller RNG (default, blocking)
1 – f(address, global_statement)
2 – constant 1
3 – serial counter
4 – object address
5 – Thread-local Xorshift

根据应用程序,您可能会在.hashcode()调用时看到意外的性能下降,当这种情况发生时,您可能正在使用共享全局状态和/或块的算法之一。

于 2022-01-11T11:43:31.170 回答
0

来自 Javadoc:

在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但 Java™ 编程语言不需要这种实现技术。)

https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--

于 2018-01-05T17:46:28.467 回答