下面是正确的equals和hashCode在Java中的实现吗?

下面是正确的equals和hashCode在Java中的实现吗?,java,hashcode,Java,Hashcode,当一个对象的值相等时,我需要返回它为真 范例 @Override public int hashCode() { return new HashCodeBuilder().append(value).toHashCode(); } @Override public boolean equals(final Object obj) { if (obj instanceof NumberValTO) { final NumberValTO other = (NumberVal) obj;

当一个对象的值相等时,我需要返回它为真

范例

@Override
public int hashCode() {
return new HashCodeBuilder().append(value).toHashCode();
}

@Override
public boolean equals(final Object obj) {
if (obj instanceof NumberValTO) {
  final NumberValTO other = (NumberVal) obj;
  return new EqualsBuilder().append(value, other.getValue()).isEquals();
}
return false;
}
以上是正确的还是错误的

我在一些应用程序中看到哈希代码在表的每个字段都是多个的,并且不确定这是否是一种正确的方法

假设一个实体有4列 假设一个实体有两列

  • 哪种方法是产生相同结果的最佳方法
  • 另外,我们是否需要为hibernate实体类实现hashcode()和equals()

  • 谢谢。

    您的示例很好,因为它提供了equals和hashcode方法的公平实现。我在我的项目中使用这种方式

    要回答你1个问题,你可以通读


    要回答您的2个问题,请点击链接:

    是的,这很好,假设您正在使用的是Apache Commons helper类@Vino指出添加
    if(obj==this)返回true是正确的equals
    方法的开头,code>是一个值得优化的方法,但是您的方法看起来是正确的。

    您的
    equals
    hashCode
    方法都正确地使用了Apache的和,尽管您应该添加一个参考检查-
    if(obj==此)将true
    -返回到
    equals
    方法

    我最近反对使用的一个论点是,它的性能较差,所以我对它进行了测试

    我创建了一个
    HashMap
    ,添加了10K个条目,然后比较了同一个键对象的查找时间,一次使用传统的
    equals
    hashCode
    ,然后再次使用and。其思想是,通过键获取值将敲打
    equals
    hashCode
    方法,并对它们的性能进行很好的比较

    虽然实现速度较慢,但差异在60纳秒的范围内,实现的平均查找时间约为320纳秒,传统方法的平均查找时间约为260纳秒(我在下面展示了我使用的代码)

    IMHO只有在大量对象上重复调用
    equals
    hashCode
    时,才应该考虑这种性能损失,即使如此,也只有在牺牲代码清晰度的情况下,才值得牺牲较小的性能增益

    不管怎样,下面是我用来测试性能差异的类:

    public class Example
    {
      private Type operationType;
      private long identity;
      private String name;
      private BigDecimal value;
    
      public Example(Type operationType, long identity, String name, BigDecimal value)
      {
        this.operationType = operationType;
        this.identity = identity;
        this.name = name;
        this.value = value;
      }
    
      public Example(Example example)
      {
        this.operationType = example.operationType;
        this.identity = example.identity;
        this.name = example.name;
        this.value = example.value;
      }
    
      public long getIdentity()
      {
        return identity;
      }
    
      public String getName()
      {
        return name;
      }
    
      public BigDecimal getValue()
      {
        return value;
      }
    
      @Override
      public boolean equals(Object obj)
      {
        if (Type.TRADITIONAL.equals(operationType))
        {
          if (this == obj)
          {
            return true;
          }
          if (obj == null || getClass() != obj.getClass())
          {
            return false;
          }
    
          Example example = (Example)obj;
          return getIdentity() == example.getIdentity()
            && ((getName() == null && example.getName() == null) || getName().equals(example.getName ()))
            && ((getValue() == null && example.getValue() == null) || getValue().equals(example.getValue()));
        }
        else
        {
          return this == obj || obj instanceof Example &&
            new EqualsBuilder()
              .append(getIdentity(), ((Example)obj).getIdentity())
              .append(getName(), ((Example)obj).getName())
              .append(getValue(), ((Example)obj).getValue())
              .isEquals();
        }
      }
    
      @Override
      public int hashCode()
      {
        if (Type.TRADITIONAL.equals(operationType))
        {
          int result = (int)(getIdentity() ^ (getIdentity() >>> 32));
          result = 31 * result + (getName() != null ? getName().hashCode() : 0);
          result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
          return result;
        }
        else
        {
          return new HashCodeBuilder().append(getIdentity()).append(getName()).append(getValue()).toHashCode();
        }
      }
    
      public static enum Type
      {
        TRADITIONAL,
        COMMONS
      }
    }
    
    下面是测试:

    public class ExampleTest
    {
      @Test
      public void testMapLookupWithTraditional() throws Exception
      {
        double total = 0;
    
        for (int i = 0; i < 10; i++)
        {
          total += testMapLookup(Example.Type.TRADITIONAL);
        }
    
        System.out.println("Overall Average: " + (total / 10));
      }
    
      @Test
      public void testMapLookupWithCommons() throws Exception
      {
        double total = 0;
    
        for (int i = 0; i < 10; i++)
        {
          total += testMapLookup(Example.Type.COMMONS);
        }
    
        System.out.println("Overall Average: " + (total / 10));
      }
    
      private double testMapLookup(Example.Type operationType) throws Exception
      {
        Map<Example, String> examples = new HashMap<Example, String>();
    
        while (examples.size() < 10000)
        {
          long now = System.currentTimeMillis();
    
          Example example = new Example(
            operationType,
            now,
            "EXAMPLE_" + now,
            new BigDecimal(now)
          );
    
          examples.put(example, example.getName());
          Thread.sleep(1);
        }
    
        int count = 0;
        double average = 0;
        double max = 0;
        double min = Double.MAX_VALUE;
    
        for (Example example : examples.keySet())
        {
          Example copiedExample = new Example(example);
    
          long start = System.nanoTime();
    
          examples.get(copiedExample);
    
          long duration = System.nanoTime() - start;
    
          average = ((average * count++) + duration) / count;
    
          if (max < duration) max = duration;
          if (min > duration) min = duration;
        }
    
        System.out.println("Average: " + average);
        System.out.println("Max: " + max);
        System.out.println("Min: " + min);
    
        return average;
      }
    }
    
    公共类示例测试
    {
    @试验
    public void testMapLookupWithTraditional()引发异常
    {
    双倍合计=0;
    对于(int i=0;i<10;i++)
    {
    total+=testMapLookup(Example.Type.TRADITIONAL);
    }
    系统输出打印项次(“总平均:+(总计/10));
    }
    @试验
    public void testMapLookupWithCommons()引发异常
    {
    双倍合计=0;
    对于(int i=0;i<10;i++)
    {
    total+=testMapLookup(Example.Type.COMMONS);
    }
    系统输出打印项次(“总平均:+(总计/10));
    }
    私有双testMapLookup(Example.Type operationType)引发异常
    {
    Map examples=newhashmap();
    while(示例.size()<10000)
    {
    long now=System.currentTimeMillis();
    示例=新示例(
    操作类型,
    现在
    “示例”+现在,
    新的BigDecimal(现在)
    );
    put(例如,example.getName());
    睡眠(1);
    }
    整数计数=0;
    双平均=0;
    双最大值=0;
    双最小值=双最大值;
    例如(示例:examples.keySet())
    {
    示例copiedExample=新示例(示例);
    长启动=System.nanoTime();
    示例.get(复制示例);
    长持续时间=System.nanoTime()-开始;
    平均=((平均*计数++)+持续时间)/计数;
    如果(最大值<持续时间)最大值=持续时间;
    如果(分钟>持续时间)分钟=持续时间;
    }
    System.out.println(“平均值:+平均值”);
    System.out.println(“Max:+Max”);
    System.out.println(“Min:+Min”);
    收益率平均值;
    }
    }
    
    取决于HashCodeBuilder
    &
    equalBuilder
    的功能。里面可能有乘法(正确性不需要乘法-请参阅)。您的
    equals
    方法还应该与null进行比较,并与self进行比较(
    this
    )。例如,与
    相比,这是一个好主意,尽管它只是一个性能优化
    null
    检查已经包括在内,因为
    null instanceof any
    false
    。感谢链接。您是否发现上述hashcode或equals中存在任何问题??为什么我们需要编写自己的逻辑而不是使用上面的???@Vino
    instanceof
    返回false表示null,与
    相比,这纯粹是性能优化。方法很好。非常感谢你的回答