简体   繁体   English

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

[英]Is the below is correct equals and hashCode implementation in Java?

When an object's value is equal i need to return it is true. 当一个对象的值相等时,我需要返回它为true。

example

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

Is the above is fine or wrong? 以上是好的还是错误的?

I saw in few applications where hashcode is being multiple with each and every field of the table and not sure whether it is a correct approach. 在少数应用程序中,我看到哈希码在表的每个字段中都为多个,并且不确定是否正确。

Assume an entity has 4 columns Assume an entity has 2 columns 假设一个实体有4列假设一个实体有2列

  1. Which is the best approach to generate the same? 哪一种是生成相同内容的最佳方法?
  2. Also, do we need to implement hashcode() and equals() for a hibernate entity class? 另外,我们是否需要为休眠实体类实现hashcode()和equals()?

Thanks. 谢谢。

Your example is fine as it provides a fair implementation of equals and hashcode methods. 您的示例很好,因为它提供了equals和hashcode方法的公平实现。 I am using this way in my project. 我在项目中使用这种方式。

To answer you 1 question You can read through http://www.ideyatech.com/2011/04/effective-java-equals-and-hashcode/ 为您解答1个问题您可以阅读http://www.ideyatech.com/2011/04/effective-java-equals-and-hashcode/

To answer you 2 question follow link : Hibernate: When is it necessary to implement equals() and hashCode(), and if so, how? 要回答2个问题,请点击以下链接: 休眠:什么时候需要实现equals()和hashCode(),如果需要,如何实现?

Yes it's fine, assuming those are the Apache Commons helper classes you're using. 是的,这很好,假设这些是您正在使用的Apache Commons帮助器类。 @Vino is correct to point out that adding if (obj == this) return true; @Vino是正确的,指出添加if (obj == this) return true; to the start of your equals method can be a worthwhile optimisation, but your methods look correct as is. equals方法的开始可能是一个值得优化的方法,但是您的方法看起来仍然正确。

Your equals and hashCode methods are both using the EqualsBuilder and HashCodeBuilder from Apache's commons-lang correctly, though you should add a reference check - if (obj == this) return true - to the equals method. 您的equalshashCode方法都正确地使用了Apache commons-langEqualsBuilderHashCodeBuilder ,尽管您应该向equals方法添加引用检查- if (obj == this) return true equals

An argument I've recently been given against using EqualsBuilder and HashCodeBuilder was that it was less performant, so I tested it. 我最近被反对使用EqualsBuilderHashCodeBuilder的一个论据是它的性能较差,因此我对其进行了测试。

I created a HashMap , added 10K entries and then compared the look-up times for the same key object, once using a traditional equals and hashCode , then again with the EqualsBuilder and HashCodeBuilder . 我创建了一个HashMap ,添加了1万个条目,然后比较了相同键对象的查找时间,一次使用了传统的equalshashCode ,然后再次使用了EqualsBuilderHashCodeBuilder The idea is that getting the values by their key will hammer the both the equals and hashCode methods and give a good comparison of their performance. 想法是,通过键获取值将锤击equalshashCode方法,并对其性能进行良好的比较。

While the EqualsBuilder and HashCodeBuilder implementations where slower, the difference was in the region of 60ns with an average look-up time of about 320ns for the commons-lang implementation and 260ns for the traditional approach (I've shown the code I used below). 尽管EqualsBuilderHashCodeBuilder实现的速度较慢,但​​差异在60ns左右, commons-lang实现的平均查找时间约为320ns,传统方法的平均查找时间为260ns(我在下面展示了我使用的代码) 。

IMHO this performance penalty should only be a concern where the equals and hashCode are called repeatedly over a large set of objects and even then, only where the small performance gain is worth sacrificing that clarity of you code. 恕我直言,只有在大量对象上反复调用equalshashCode情况下,才应该考虑这种性能损失,即使在这种情况下,只有很小的性能提升就值得牺牲代码的清晰度。

Anyway, here's the class I used to test the performance difference: 无论如何,这是我用来测试性能差异的类:

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

And here's the test: 这是测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM