简体   繁体   中英

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.

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

  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?

Thanks.

Your example is fine as it provides a fair implementation of equals and hashcode methods. 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/

To answer you 2 question follow link : Hibernate: When is it necessary to implement equals() and hashCode(), and if so, how?

Yes it's fine, assuming those are the Apache Commons helper classes you're using. @Vino is correct to point out that adding if (obj == this) return true; to the start of your equals method can be a worthwhile optimisation, but your methods look correct as is.

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.

An argument I've recently been given against using EqualsBuilder and HashCodeBuilder was that it was less performant, so I tested it.

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

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).

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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