代码之家  ›  专栏  ›  技术社区  ›  James McMahon

如何在hashCode()中将long映射到int?

  •  45
  • James McMahon  · 技术社区  · 14 年前

    long 其值在整个系统中唯一标识特定对象的字段,非常类似于GUID。我已经超越了 Object.equals() 为了使用这个id进行比较,因为我希望它能够处理对象的副本。现在我想重写 Object.hashCode() 也就是说 长的 对某些人 int 返回值。

    如果我明白 hashCode id % 2^32 就够了。就这些,还是我应该知道其他的事情?

    6 回复  |  直到 14 年前
        1
  •  88
  •   hotkey    9 年前

    因为Java8你可以使用

    Long.hashCode(guid);
    

    对于旧版本的Java,可以使用以下命令:

    Long.valueOf(guid).hashCode();
    

    注意,这个解决方案为堆栈创建了一个新对象,而第一个没有(尽管Java很可能优化了对象的创建)

    查看文档时,两种方法都使用以下算法:

    (int)(this.longValue()^(this.longValue()>>>32))
    

    这些都是不错的解决方案,因为它们利用了Java库——总是更好地利用已经测试过的东西。

        2
  •  9
  •   ColinD    13 年前

    如果你不使用 Guava 已经有了,但是番石榴可以 do this for you 很好地:

    public int hashCode() {
      return Longs.hashCode(id);
    }
    

    这就相当于 Long.valueOf(id).hashCode() :

    return (int) (value ^ (value >>> 32));
    

    return Objects.hashCode(longValue, somethingElse, ...);
    

    这个 long 会变成一个 Long 所以你会得到正确的hashcode作为整个hashcode的一部分。

        3
  •  5
  •   Grodriguez    14 年前

    你已经明白了 hashCode 正确地。是的,均匀分布是可取的(虽然不是实际要求)。

    ((id >> 32) ^ id) .

    上述表达式:

    • 使用原始值的所有位,不会预先丢弃任何信息。例如,根据生成id的方式,高位的变化可能更频繁(或相反)。
    • 不会对多个1(零)的值引入任何偏差,因为如果将两个半部分与或(和)操作组合在一起,则会出现这种情况。
        4
  •  3
  •   Community CDub    7 年前

    Java 8添加 Long.hashCode(long) 去JDK。

    下面的代码可以产生更高的性能。此代码将计算减少到32位 int 而不是用64位计算 long

    return (int)(value ^ (value >>> 32));

    正如在其他答案中所指出的,这是 祝你愉快 avalanche effect 因此可能导致碰撞。可以使用加密散列函数来确保高雪崩效应。不过,还有其他算法,如 Murmur Hash information )它有很好的雪崩效果,但不会占用太多的CPU时间。

        5
  •  1
  •   codymanix    14 年前
    int result = (int)((longVal >> 32) ^ longVal);
    

    将更均匀地分布,因为如果长值的高位发生变化,模将不会返回不同的值。

        6
  •  1
  •   Mark Peters    14 年前

    (l >> 32) ^ l 在大多数情况下是一个好的哈希代码;特别是当long有一个统一的分布时。

    我举的例子是这样一个点类:

    public class Point {
        private final long coords; //x in high-bits, y in low
        public int getX() {
            return (int)(coords >> 32);
        }
        public int getY() {
            return (int)coords;
        }
        public int hashCode() {
            return (int)((coords >> 32) ^ (coords));
        }
    }
    

    所以 coords

    00000000 00000000 000000XX XXXXXXXX 00000000 00000000 000000YY YYYYYYYY
    

    有2^20(1024*1024)种可能的组合。但是hashCode在做什么呢?

      00000000 00000000 000000XX XXXXXXXX 
    ^ 00000000 00000000 000000YY YYYYYYYY
    -------------------------------------
    = 00000000 00000000 000000?? ????????
    

    1024:(1024*1024) 1:1024 . 所以马上就有1/1024的概率两个数字有相同的散列。

    birthday problem . 设p(n)为n值时至少发生一次碰撞的概率。我们知道p(1025+)=1,因为只有1024个值。

    p(n) = 1 - (n! * (1024 choose n))/1024^n
    

    n: p(n)
    1: 0.00000
    2: 0.00098
    3: 0.00293
    4: 0.00585
    5: 0.00973
    6: 0.01457
    ...
    38: 0.50096
    ...
    79: 0.95444
    ...
    148: 0.99999
    

    只有38件,可能有碰撞。有148件物品,有99.999%的几率(至少一件)发生碰撞。有148件物品,每件物品与另一件物品碰撞的几率为7%。通过适当的散列函数,获取域的知识,这些数字很容易降到0。