有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Apache Commons HashCodeBuilder:数值类型为空与零

最近,我在使用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(),但不幸的是,我正在使用的代码库正在比较两个Object,这意味着我无法了解equals()hashcode()是否为任何给定的输入实际定义,我无法编辑类定义以在缺少这些方法的情况下添加这些方法。这可能就是该代码的原始作者选择使用reflectionHashCode()的原因。考虑到这一点,是否有基于编程/代码的解决方案或解决方案来解决此问题,例如不需要在被比较的对象上定义equals()hashcode()的替代库


共 (2) 个答案

  1. # 1 楼答案

    基于代码的解决方案是以区分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)不太可能导致与有效短值的冲突

  2. # 2 楼答案

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