tags:

views:

81

answers:

2

I am having a java class Rec. I have two instance of it Rec1 and Rec2. I want to check whether the values of Rec1 and Rec2 are equal. If i do Rec1.equals(Rec2) is it correct way of doing it?

class Rec {

  private BigDecimal  RecordId = null; 

  private BigDecimal recSubNum = null; 

  private BigDecimal  FileId = null;

  private String    Category = null; 

  private BigDecimal status = null; 

  private BigDecimal errorCode = null; 

} 
+3  A: 

You need to implement the equals() and hashCode() methods to implement object equality in Java:

class Rec {
  private BigDecimal recordId = null;
  private BigDecimal recSubNum = null;
  private BigDecimal FileId = null;
  private String category = null;
  private BigDecimal status = null;
  private BigDecimal errorCode = null;

  @Override
  public int hashCode() {
    int ret = 41;
    ret = hc(ret, recordId);
    ret = hc(ret, recSubNum);
    ret = hc(ret, fieldId);
    ret = hc(ret, category);
    ret = hc(ret, status);
    ret = hc(ret, errorCode);
    return ret;
  }

  @Override
  public boolean equals(Object ob) {
    if (ob == null) return false;
    if (ob.getClass() != Rec.class) return false;
    Rec r = (Rec)ob;
    if (!eq(r.recordId, record)) return false;
    if (!eq(r.recSubNum, recSubNum)) return false;
    if (!eq(r.fileId, fileId)) return false;
    if (!eq(r.category, category)) return false;
    if (!eq(r.status, status)) return false;
    if (!eq(r.errorCode, errorCode)) return false;
    return true;
  }

  private static boolean eq(Object ob1, Object ob2) {
    return ob1 == null ? ob2 == null : ob1.equals(ob2);
  }

  private static int hc(int hc, Object field) {
    return field == null ? hc : 43 + hc * field.hashCode();
  }
}

Note: the equals/hashCode contract for Java means that for any two objects a and b:

a.equals(b) == b.equals(a)

and if two objects are equal then a.hashCode() must equal b.hashCode().

Edit: there are two ways of checking if the types match. Either:

if (ob == null) return false;
if (ob.getClass() != Rec.class) return false;

or

if (!(ob instanceof Rec)) return false;

These two do different things and you should select the correct one depending on what you want to do. I generally prefer the first one unless you know you need the second. What's the difference?

class A {
  public int i;

  public boolean equals(Object ob) {
    if (!(ob instanceof A)) return false;
    return i == ((A)ob).i;
  }
}

Looks reasonable right? What if the class gets extended:

class B extends A {
  public int j;

  public boolean equals(Object ob) {
    if (!(ob instanceof B)) return false;
    if (!super.equals(ob)) return false;
    return j == ((B)ob).j;
  }
}

Still looks reasonable? It's broken.

A a = new A();
a.i = 10;
B b = new B();
b.i = 10;
b.j = 20;
System.out.println(a.equals(b)); // true! Is this really what you want?
System.out.println(b.equals(a)); // false! Different to previous = problem.

That's why I favour getClass() over instanceof unless I really want subclass equality.

cletus
@arav, here's a related article you might want to read: http://www.javapractices.com/topic/TopicAction.do?Id=17@cletus +1 for the full answer :)
o.k.w
This works well, but the Apache EqualsBuilder and HashCodeBuilder from apache lang http://commons.apache.org/lang/ make this trivial.
Jeff Storey
+1, cheers for that -- something I didn't know existed. Might be relevant to my interests in the future :)
Chris Dennett
The contract also includes that the two objects should be the same concrete class and that o.equals(null) == falseThe code in this comment will throw a NullPointerException if passed a null.Apache EqualsBuilder and HashCodeBuilder do make it easy, but you still have to do the class match and null check.
Don Roby
Instead of calling `ob.getClass().equals(Rec.class)`, use `ob instanceof Rec` - this will return false if `ob` is null, instead of throwing the NullPointerException.
rjohnston
@rjohnston: there's a problem with `instanceof`. See the update.
cletus
@cletus that's really swapping one problem for another, but I can see how making `equals` fail for subclasses by default would be desirable. I was mainly concerned with your initial definition breaking the a.equals(null) part of the contract, which you've fixed now, so it's all good
rjohnston
A: 

if Rec is a user defined class then you really should override the equals method otherwise it will just call the equals method in the Object class;

something like :

public boolean equals(Rec x){
    //check here to see if the references are the same, if so return true
    if(this == x) return true;

    //if they aren't the same object then check all the fields for equality
    if (category.equals(x.category) && etc etc) return true;
    else return false;
}
CheesePls