【问题标题】:Is the below is correct equals and hashCode implementation in Java?以下是Java中正确的equals和hashCode实现吗?
【发布时间】:2014-03-10 09:53:14
【问题描述】:

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

例子

@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 列 假设一个实体有 2 列

  1. 生成相同的最佳方法是什么?
  2. 另外,我们是否需要为休眠实体类实现 hashcode() 和 equals()?

谢谢。

【问题讨论】:

  • 取决于 HashCodeBuilderEqualsBuilder 做什么。里面可能有乘法(这不是正确性所必需的 - 请参阅this question)。
  • 您的 equals 方法还应该与 null 比较并与 self (this) 比较。例如看到这个link
  • this 比较是一个好主意,尽管它只是一个性能优化。 null 检查已包含,因为 null instanceof Anythingfalse
  • 感谢您的链接。你在上面的 hashcode 或 equals 中看到任何问题吗?为什么我们需要编写自己的逻辑而不是使用上面的??
  • @Vino instanceof 为 null 返回 false,与 this 比较纯粹是性能优化。方法很好。

标签: java hashcode


【解决方案1】:

是的,这很好,假设这些是您正在使用的 Apache Commons 辅助类。 @Vino 正确地指出,将 if (obj == this) return true; 添加到 equals 方法的开头可能是值得优化的,但您的方法看起来是正确的。

【讨论】:

  • 非常感谢您的所有回答
【解决方案2】:

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

回答你1个问题你可以通读http://www.ideyatech.com/2011/04/effective-java-equals-and-hashcode/

要回答你 2 个问题,请点击链接:Hibernate: When is it necessary to implement equals() and hashCode(), and if so, how?

【讨论】:

    【解决方案3】:

    您的equalshashCode 方法都正确地使用了来自Apache 的commons-langEqualsBuilderHashCodeBuilder,尽管您应该在equals 方法中添加一个引用检查-if (obj == this) return true

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

    我创建了一个HashMap,添加了 10K 个条目,然后比较了同一键对象的查找时间,一次使用传统的 equalshashCode,然后再次使用 EqualsBuilderHashCodeBuilder .这个想法是,通过键获取值将锤击equalshashCode 方法,并很好地比较它们的性能。

    虽然 EqualsBuilderHashCodeBuilder 实现速度较慢,但​​差异在 60ns 左右,commons-lang 实现的平均查找时间约为 320ns,而传统方法的平均查找时间为 260ns(我已经显示了我在下面使用的代码)。

    恕我直言,这种性能损失应该只在equalshashCode在大量对象上被重复调用时才值得关注,即使这样,只有在小的性能提升值得牺牲代码的清晰度的情况下。

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

    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;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-02
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      相关资源
      最近更新 更多