简体   繁体   中英

Comparing two instances of class having big number of attributes

I have a class having more than 30 attributes.

I want to override the equals method in order to compare two instance of my class.

However I want to avoid re-write all the 30 attributes in my method as this

@Override
public boolean equals(java.lang.Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    Address address = (Address) o;
    return Objects.equals(this.attr1, address.attr1) &&
            Objects.equals(this.attr2, address.attr2) &&
            Objects.equals(this.attr3, address.attr3) &&
            ......
            Objects.equals(this.attr30, address.attr30);

}

Have you a more simple and proper way ?

You have this method in apache commons library that uses reflection for compare them

org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(Object, Object)

Example

import org.apache.commons.lang.builder.EqualsBuilder;

public class MyObject {

   ...
   @Override
   public boolean equals(Object obj) {
      return EqualsBuilder.reflectionEquals(this, obj);
  }
}

您可以使用lombok项目在构建时自动生成hashCode和equals方法。

You can use the Field class in the java.lang.reflect package like so:

@Override
public boolean equals(Object o) {
    //instanceof check, null check, etc

    Field[] fields = Address.class.getDeclaredFields();

    for (Field field : fields) {
        try {
            field.setAccessible(true);

            if (!field.get(this).equals(field.get((Address) o))) {
                return false;
            } //end if
        } catch (IllegalAccessException e) {
            //handle exception
        } //end try catch
    } //end for

    return true;
} //equals

Well, this is basically the type of boilerplate code that is necessary. Luckily, there are lots of developers just as annoyed of writing such code as you are. For reasons like that, Project Lombok was founded.

Please see this link.

As an example, see the following two code snippets extracted from the page that I linked above:

Lombok

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  public String getName() {
    return this.name;
  }

  @EqualsAndHashCode(callSuper=true)
  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

Vanilla Java

import java.util.Arrays;

public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  public String getName() {
    return this.name;
  }

  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof EqualsAndHashCodeExample)) return false;
    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (Double.compare(this.score, other.score) != 0) return false;
    if (!Arrays.deepEquals(this.tags, other.tags)) return false;
    return true;
  }

  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.score);
    result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME) + Arrays.deepHashCode(this.tags);
    return result;
  }

  protected boolean canEqual(Object other) {
    return other instanceof EqualsAndHashCodeExample;
  }

  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }

    @Override public boolean equals(Object o) {
      if (o == this) return true;
      if (!(o instanceof Square)) return false;
      Square other = (Square) o;
      if (!other.canEqual((Object)this)) return false;
      if (!super.equals(o)) return false;
      if (this.width != other.width) return false;
      if (this.height != other.height) return false;
      return true;
    }

    @Override public int hashCode() {
      final int PRIME = 59;
      int result = 1;
      result = (result*PRIME) + super.hashCode();
      result = (result*PRIME) + this.width;
      result = (result*PRIME) + this.height;
      return result;
    }

    protected boolean canEqual(Object other) {
      return other instanceof Square;
    }
  }
}

If you like this approach, I'd recommend checking out Project Lombok in its entirety. It really helps cleaning up your code!

!!! Beware !!! In order to be able to actually use methods generated by Lombok, you need to install the Lombok plugin into your IDE! Otherwise, your IDE won't know of the automatically generated methods.

You can use Unitils http://www.unitils.org/cookbook.html

import static org.unitils.reflectionassert.ReflectionAssert.*;
// Exact field-by-field comparison
assertReflectionEquals(new Person("John", "Doe", new Address("New street", 5, "Brussels")), 
                             new Person("John", "Doe", new Address("New street", 5, "Brussels"));

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