Java ApacheCommonsHashCodeBuilder:数值类型为null与零

Java ApacheCommonsHashCodeBuilder:数值类型为null与零,java,apache-commons-lang3,hash-code-uniqueness,Java,Apache Commons Lang3,Hash Code Uniqueness,最近,我在使用Apache Commons Lang 3的Java代码库中遇到了以下hashcode“equality”场景,我很惊讶地发现,对于如何处理看似常见的问题,我找不到太多信息: MyObject one = new MyObject(); one.setFoo("foo"); one.setBar(null); MyObject two = new MyObject(); two.setFoo("foo"); two.setBar((short) 0); int oneHash

最近,我在使用Apache Commons Lang 3的Java代码库中遇到了以下hashcode“equality”场景,我很惊讶地发现,对于如何处理看似常见的问题,我找不到太多信息:

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()));
前面的代码生成以下输出,这表明两个对象具有相同的hashcode,尽管它们不相等:

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;
    }
}
虽然我可以从纯数学的角度理解空数值和0数值具有相同的散列,但在任何实际设置中,这都会导致非相等对象具有相同的散列代码,这可能会导致相当严重的冲突问题


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

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

基于代码的解决方案是以区分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);
    }
}

由于
bar
是一个
Short
,因此超出
Short
有效范围的值(如1234567)不太可能与有效的Short值发生冲突。

您需要做的第一件事是停止使用
HashCodeBuilder.reflectionHashCode()
,因为该方法无法提供足够的控制。如果出于某种原因不想使用标准库对象类,那么您可以使用HashCodeBuilder中的其他方法。因此,您使用的代码使用的函数来自不符合您需要的开放源代码库(HashCodeBuilder.reflectionHashCode),并且您无法更改代码以使其使用其他函数。这是对您的情况的正确描述吗?相反:我可以更改进行哈希和比较的代码,但我不能更改基础对象以添加
equals()
hashcode()
。这是否意味着您可以使计算哈希的代码将
null
视为非0的数字?是的,我可以,从理论上讲,完全靠我自己重新实现reflectionHashCode(),但这似乎不是一个实际的解决方案。