【问题标题】:Why Hash Code of different Boolean instances is always the same?为什么不同布尔实例的哈希码总是相同的?
【发布时间】:2014-05-06 04:35:41
【问题描述】:

在下面的代码中,哈希码总是相同的。为什么会这样?

代码:

public class BooleanClass {

    public static void main(String[] args) {
        Boolean b1 = new Boolean(true);
        Boolean b2 = new Boolean(false);
        Boolean b3 = new Boolean(true);
        Boolean b4 = new Boolean(false);
        Boolean b5 = new Boolean(false);
        Boolean b6 = new Boolean(true);

        System.out.println(b1.hashCode());
        System.out.println(b2.hashCode());
        System.out.println(b3.hashCode());
        System.out.println(b4.hashCode());
        System.out.println(b5.hashCode());
        System.out.println(b6.hashCode());
    }
}

输出:

1231
1237
1231
1237
1237
1231

总是打印相同的数字12311237。有什么原因吗?

【问题讨论】:

  • 如果两个对象相等(在 equals 方法的意义上),它们应该(最好必须)也有相同的哈希码。
  • @Seelenvirtuose 来自 Javadoc:如果两个对象根据 equals(Object) 方法相等,则对两个对象中的每一个调用 hashCode 方法必须 产生相同的整数结果。(强调我的)。所以你的应该太弱了。
  • @BoristheSpider 知道了。 :-) 但事实上,必须并不是严格的技术要求。因此,您可以实现产生不同哈希码的 hashCode 方法(例如 Object.hashCode 所做的)。嗯……更深入的思考……在处理哈希数据结构(例如 HashMap)时,它成为了一项技术要求,因为它们需要以这种方式实现的 hashCode 方法,Javadoc 解释说。所以,你是完全正确的。
  • 始终返回 0 的 hashCode() 根据定义是正确的实现,如果另一个实现依赖于“更正确”的 hashCode() 来提供正确的结果,那么这个另一个实现就会被破坏。
  • 我要补充一点,使用盒装 Boolean非常浪费。但是由于只有两个值,而且布尔值是不可变的,如果需要对象,可以使用预定义的Boolean.TRUEBoolean.FALSE 而不是创建新对象。

标签: java boolean hashcode


【解决方案1】:

Boolean.hashCode()The JavaDoc 方法说:

如果此对象表示true,则返回整数1231;如果此对象表示false,则返回整数1237

【讨论】:

  • 如果你把这个加到你的答案中,这将是最好的答案:“如果两个对象根据equals(Object)方法相等,那么对这两个对象分别调用hashCode()方法对象必须产生相同的整数结果。”
  • @WhoAmI:查看this answer 以获得解释。
  • 总结the answer Keppil linked to:1231 和 1237 只是两个任意素数,目的是减少哈希集/哈希映射中的冲突。
【解决方案2】:

hashCode() 的合约是:

如果两个对象根据equals(Object) 方法相等,那么对两个对象中的每一个调用hashCode() 方法必须产生相同的整数结果。

虽然 boolean 只有两个值,truefalse,但您只能得到两个不同的哈希码。

【讨论】:

    【解决方案3】:

    直接来自布尔类:

     public int hashCode()
     {
       return ((this.value) ? 1231 : 1237);
     }
    

    这是为布尔类型生成哈希码的方法。这就是为什么你总是得到相同的真假哈希码。

    这是布尔的构造函数

     public Boolean(boolean paramBoolean)
     {
       this.value = paramBoolean;
     }
    

    所以 this.value 要么为真要么为假,如果为真,则返回 1231,如果为假,则返回 1237

    【讨论】:

      【解决方案4】:

      散列函数的要点是将任意长度的数据映射到固定长度的数据。散列函数返回的值称为散列值、散列码、散列和、校验和或简称为散列。如果输入相同,哈希函数将始终返回完全相同的哈希,因此哈希 true 将始终等于 1231 并且哈希 false 将始终等于 1237

      【讨论】:

        【解决方案5】:

        如果你真的需要区分实例而不是值——这很少是你真正想要的,但它偶尔会发生——请参阅IdentityHashMap

        (本质上,IdentityHashMap 绕过了对象“真实”类中的 .equals().hashcode() 实现,并使用来自 Object 的实现。)

        【讨论】:

          【解决方案6】:

          我不明白为什么这个问题会引起如此多的关注。如果不是这样,我会感到惊讶。由于其他人很好地指出了它,甚至在documentation中指定了它。

          但是即使没有文档,也很容易理解原因:你可以查看哈希函数的定义function

          哈希函数是将任意长度的数据映射到 固定长度的数据。

          而来自mathematical definition的map是一个函数,这意味着相同的值总是会产生相同的值。

          如果这没有帮助,你可以看看这个例子:

           int a = 400;
           int b = 400;
          

          您是否应该期望哈希值会有所不同?很可能没有。那么为什么它们在真假的情况下要不同呢?

          【讨论】:

          • 好主意,但没有。在编程语言中,“函数”与数学函数不同(明显的示例:有状态或上下文相关的函数可能会为相同的参数返回不同的数据)。相反,这直接来自于哈希表的设计,它要求两个 equal() 值预期具有相同的 hashCode()。
          猜你喜欢
          • 1970-01-01
          • 2020-06-22
          • 2015-12-21
          • 2012-09-24
          • 1970-01-01
          • 2015-09-08
          • 1970-01-01
          • 2012-08-13
          • 2017-11-15
          相关资源
          最近更新 更多