【问题标题】:Apache Commons HashCodeBuilder: null vs zero for Numeric typesApache Commons HashCodeBuilder:数字类型的 null 与零
【发布时间】:2020-07-31 12:51:19
【问题描述】:

最近我在使用 Apache Commons Lang 3 的 Java 代码库中遇到了以下哈希码“相等”场景,令我感到惊讶的是,我找不到太多关于如何处理看似常见问题的信息:

MyObject one = new MyObject();
one.setFoo("foo");
one.setBar(null);

MyObject two = new MyObject();
two.setFoo("foo");
two.setBar((short) 0);

int oneHash = HashCodeBuilder.reflectionHashCode(one);
int twoHash = HashCodeBuilder.reflectionHashCode(two);

System.out.println("oneHash: " + oneHash);
System.out.println("twoHash: " + twoHash);
System.out.println("Bar equality: " + Objects.equals(one.getBar(), two.getBar()));

前面的代码产生以下输出,这表明两个对象具有相同的哈希码,尽管它们不相等:

oneHash: 3781511
twoHash: 3781511
Bar equality: false

MyObject 定义:

public class MyObject {
    private String foo;
    private Short bar;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public Short getBar() {
        return bar;
    }

    public void setBar(Short bar) {
        this.bar = bar;
    }
}

虽然我可以理解一个 null Numeric 和 0 Numeric 在纯数学意义上具有相同的哈希值,但在任何实际设置中,这都会导致不相等的对象具有相同的哈希码,这可能会导致相当严重的冲突问题。

澄清/复杂情况:虽然我希望能够在对象上调用 equals()hashcode(),但不幸的是,我正在使用的代码库正在比较两个 Objects,这意味着我没有洞察力equals()hashcode() 是否实际上是为任何给定输入定义的,并且我无法编辑类定义以在缺少这些方法的情况下添加这些方法。这可能是这段代码的原作者选择使用reflectionHashCode() 的原因。考虑到这一点,是否有针对此问题的编程/基于代码的解决方案或解决方法,例如不需要在要比较的对象上定义 equals()hashcode() 的替代库?

【问题讨论】:

  • 因此,您正在使用的代码使用了不符合您需求的开源库 (HashCodeBuilder.reflectionHashCode) 中的函数,并且您无法更改代码以使其使用另一个函数。你的情况描述正确吗?
  • 相反:我可以更改进行散列和比较的代码,但我无法更改基础对象以添加equals()hashcode()
  • 这是否意味着您可以让计算哈希的代码将null 视为0 以外的数字?
  • 是的,理论上我可以完全靠自己重新实现reflectionHashCode(),但这似乎不是一个实用的解决方案。

标签: java apache-commons-lang3 hash-code-uniqueness


【解决方案1】:

即使对于具有完全不同值的对象,也总是存在哈希码冲突的可能性。毕竟,您将无限数量的所有可能的对象值映射到一个 32 位整数。这仍然有效,因为利用具有集合和映射之类的代码的数据结构另外使用.equals 来检查对象是否相等。

【讨论】:

    【解决方案2】:

    基于代码的解决方案是通过区分null和0的方式实现一个哈希函数。有很多方法可以做到,这里有一个:

    // this could be called hashCode, but you don't want to override hashCode
    public int yourCustomHashFunction() {
        if (bar == null) {
            return Objects.hashCode(foo, 1234567);
        } else {
            return Objects.hashCode(foo, bar);
        }
    }
    

    由于barShort,超出short 有效范围的值(如1234567)不太可能与有效的短值发生冲突。

    【讨论】:

    • 您需要做的第一件事是停止使用HashCodeBuilder.reflectionHashCode(),因为该方法无法为您提供足够的控制。如果由于某种原因不想使用标准库 Objects 类,可以使用 HashCodeBuilder 中的其他方法
    猜你喜欢
    • 2012-06-17
    • 2015-10-11
    • 2018-04-04
    • 2014-08-01
    • 2011-12-11
    • 2011-07-31
    • 2015-02-19
    • 2016-05-12
    • 1970-01-01
    相关资源
    最近更新 更多