Win a copy of Functional Reactive Programming this week in the Other Languages forum!

# equals() proper implementation

Shiva Mohan
Ranch Hand
Posts: 486

when i apply,

it seems like the equals() "return ((SortOf)o).bal == this.bal;" is not violating the contract.(if a.hashcode()!=b.hashcode() then the requirment is a.equals(b) must be false).the result i am getting false for equlas() and false for hashcode implementation too.

marc weber
Sheriff
Posts: 11343
Part of the contract (as documented under the hashCode method in Object) is...
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

In this example, instances of SortOf are defined to be equal if they have the same value for "bal." However, the hashCode implementation (code.length() * bal) could return different hashCodes for equal instances, so it violates the contract.

Please remember to cite sources for mock exam questions.
[ January 25, 2007: Message edited by: marc weber ]

David Kennedy
Ranch Hand
Posts: 33
Could you explain where the 4*2==2*2---->false calculation
comes from?

Thanks

Shiva Mohan
Ranch Hand
Posts: 486
Hi David,I applied the intailised values.thats it.

Thanks for the reply Marc.But why would i want to change the values i intaialised and make the two bal values(3,3) equal values and compare.

This question is from K&B master exam .Did you mean,for each given option do we need to intailise the values differently and execute.i think this is the part i am not getting yet.Please help on this.

Josef Wingartz
Greenhorn
Posts: 1
Hello,

if x.equals(y) == true then x.hashCode() == y.hashcode() is a requirement!
if x.hashCode() != y.hashCode() then x.equals(y) == false is a requirement!

E.g. all classes within the collection framework starting with "Hash" are
dependant on this to work as intended. See the example below:
HashSet is supposed not to accept equal members. In order to fulfil this
requirement, equals(...) and hashCode() must be overwritten correctly.

import java.util.HashSet;

public class Test1 {
public static void main(String[] args) {
// This is the first element to be added to the HashSet
SortOf a = new SortOf();
a.code = "aaaa";
a.bal = 2; // hashcode = 8

// The following element should be rejected by
// the HashSet but it is not
SortOf b = new SortOf();
b.code = "bbb";
b.bal = 2; // hashcode = 6

// The following element should be rejected by
// the HashSet as well
SortOf c = new SortOf();
c.code = "cc";
c.bal = 2;

// This one is rejected
SortOf d = new SortOf();
d.code = "dd";
d.bal = 2;

HashSet<SortOf> hs = new HashSet<SortOf>();
for (SortOf s: hs) {
System.out.println(s);
}
}
}

class SortOf {
String name;
int bal;
String code;
short rate;

public int hashCode() {
return (code.length() * bal);
}

public boolean equals(Object o) {
return ((SortOf)o).bal == this.bal;
}

public String toString() {
return "name: " + name +
",\tbal: " + bal +
",\t\tcode: " + code +
",\trate: " + rate;
}
}

Hope this helps.

marc weber
Sheriff
Posts: 11343
Originally posted by Shiva Mohan:
...But why would i want to change the values i intaialised and make the two bal values(3,3) equal values and compare.

This question is from K&B master exam .Did you mean,for each given option do we need to intailise the values differently and execute...

Without seeing the complete question, I'm not sure what's being asked. But you should usually consider these methods in a general sense -- without applying specific values that might mislead you.

In this case, the equals method says that instances with equal bal values are considered equal. According to the hashCode contract, the hashCode method must return the same value for equal instances. But that's not the case here, because even if the bal values are equal (and therefore the instances are equal), different code.length() values will result in different hashCodes. So the hashCode contract is violated.

This has nothing to do with changing any values. It's a matter of the implementation logic.

Shiva Mohan
Ranch Hand
Posts: 486

Which of the following will fulfill the equals() and hashCode() contracts for this class ? (Choose all that apply.)

a) return ((SortOf)o).bal == this.bal;

b) return ((SortOf)o).code.length() == this.code.length();

c) return ((SortOf)o).code.length() * ((SortOf)o).bal ==
this.code.length() * this.bal;

d) return ((SortOf)o).code.length() * ((SortOf)o).bal * ((SortOf)o).rate == this.code.length() * this.bal * this.rate;

Answer is C.But still i am confused.how could i check the values for each option.Can anyone please help me giving some specific values for each option and explain how that value works here.getting this hashcode and equals() is very hard for me.For each option how could we work to get the answer.
[ January 26, 2007: Message edited by: Shiva Mohan ]

marc weber
Sheriff
Posts: 11343
For complete details on the hashCode contract, see the API documentation for hashCode under Object. But for this question, the key consideration is:
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

This implies that if variables are used in implementing these methods:
• The equals method and the hashCode method should generally use the same variables. If either method introduces a different variable, then it has the potential to give results that violate the contract.
• Those variables must be used in fundamentally the same way within each method (so as not to contradict each other).
• In this example, we are given that the hashCode is (code.length() * bal). So in looking at the options for equals...
• We can rule out 'a' because it does not use code.length(). Instances would be considered equal whenever their bal values are the same. But their code.length() might differ, and this would result in different hashCodes.
• We can rule out 'b' because it does not use bal. Instances would be considered equal whenever their code.length() values are the same. But their bal values might differ, and this would result in different hashCodes.
• 'c' is acceptable because it uses the same variables (bal and code.length()) and those variables are used in fundamentally the same way (they are multiplied).
• We can rule out 'd' because it introduces a new variable, rate. This value is critical in determining whether 2 instances are equal, so if it's not included in the hashCode calculation, then there's no guarantee that the hashCodes for equal instances will be the same. (Note that this is a little different than cases 'a' and 'b', because instances that return the same hashCode are not required to be unequal.)
• Also note that variables are not required. For example, equals could be coded to always return true and hashCode could return a constant.
[ January 27, 2007: Message edited by: marc weber ]

Henry Wong
author
Marshal
Posts: 21506
84
- We can rule out 'd' because it introduces a new variable, rate. This value is critical in determining whether 2 instances are equal, so if it's not included in the hashCode calculation, then there's no guarantee that the hashCodes for equal instances will be the same. (Note that this is a little different than cases 'a' and 'b', because instances that return the same hashCode are not required to be unequal.)

Marc is absolutely correct, but IMHO, the last item is actually a bit more subtle, which deserves another mention. It not only introduces a new variable, but uses it in a way that can cause equality, when the other two variables are not equal.

If the equals() method just compared each variable individually, like so...

Then it would have been fine, as it would short circuit the rate check, if the other variables were not equal. And it is okay in the contract to have two objects to *not* be equal but with the same hashcode.

In this example, it is possible to have an object with a balance which is double of the other, but with a rate that is half of the other, and have them equal. This would violate the contract as there hashcodes are different.

Henry

marc weber
Sheriff
Posts: 11343
Originally posted by Henry Wong:
...the last item is actually a bit more subtle, which deserves another mention...

That's an excellent point, and well made! That last case is a bit delicate to address in an abstract sense (without looking at specific implementations).

As a further side note, I was trying to illustrate a general approach for reasoning through this, without plugging in specific values that could be misleading. When you use specific values as an example, that only shows something works for that particular case. It does not say anything about whether it will work for other cases. On the other hand, if you use specific values to show something does not work, then that's valid, because all you need is one counterexample to disprove something.

I used to tutor math in college, and I appreciate that many people are more comfortable working with specific values instead of variables. This is okay for getting a sense of how something works (seeing it in action), but be very careful about drawing conclusions from this.

Now, as to why Henry was awake to post at that hour on a Saturday... That's a puzzle.
[ January 27, 2007: Message edited by: marc weber ]

Henry Wong
author
Marshal
Posts: 21506
84
Now, as to why Henry was awake to post at that hour on a Saturday... That's a puzzle.

Well, I could make up something up, like travelling around Europe with a laptop...

Or I could just admit, that at my age... what I do, eat, but more importantly, drink, on a Friday, may come with a penalty.

Henry

Shiva Mohan
Ranch Hand
Posts: 486
Sorry for the late reply since i have been sick today.Thank you so much for the nice explanation Marc and Henry.I have used these implementation technique on the below program to make sure i get it correctly.
But still somewhere i am having trouble.

Given the following class, which are correct implementations of the hashCode() method?

class ValuePair {
public int a, b;
public boolean equals(Object other) {
try {
ValuePair o = (ValuePair) other;
return (a == o.a && b == o.b)
|| (a == o.b && b == o.a);
} catch (ClassCastException cce) {
return false;
}
}
public int hashCode() {
// Provide implementation here.
}
}
a) return 0;
b) return a;
c) retrun a+b;
d) return a-b;
e) return a^b;
f) return (a<<16);

My workout on the option a is:return 0;we are returning value 0.so hashcodes of the two instances are equal.so the equals() method could be true or false.(that is the expected contract) so a is acceptable.

option b :return a; returning variable a.the variable b is missing.so It looks like contract is violated .this option is ruled out.

option c:returning a+b.(not using variables must be used in fundamentally the same way within each method.).it seems like violating the contract.but this option is accetable .how

option d:returning a-b(.(since not using variables must be used in fundamentally the same way within each method.it violates

option e: return a^b;(since not using variables must be used in fundamentally the same way within each method.it looks like violates for me.but this option is accepatable.How

option f:return (a<<16);since not using variables must be used in fundamentally the same way within each method.it violates
[ January 27, 2007: Message edited by: Shiva Mohan ]

marc weber
Sheriff
Posts: 11343
"...used in fundamentally the same way..." I had a feeling that wording might be troublesome, but I'm not sure of a better way to put this. Hopefully an explanation will clear this up.

Consider how this equals method works. First, it tries to cast the other reference to type ValuePair, and if the cast fails (results in an exception), the method returns false. So other must be an instanceof ValuePair. Next, it returns true if each instance has the same pair of ints regardless of order -- that is, regardless of which value is assigned to 'a' and which to 'b'. So the "fundamental" requirement here is that 'a' and 'b' need to be interchangeable.

On to the hashCode...
• For option 'a', you are correct.
• For option 'b', you are correct, but this is really because the equals method allows for variables a and b to be interchangable. If they were not interchangeable, then this would work.
• For option 'c', a+b is the same as b+a (they are interchangeable), so this is okay.
• For option 'd', a-b is not the same as b-a, so this is not okay.
• For option 'e', a^b is the same as b^a, so this is okay. (Note that the ^ operator is not "to the power of." It is the bitwise "exclusive or" operator.)
• In option 'f', you are correct for the same reason as option 'b'.
•
Raji Rama
Greenhorn
Posts: 5
That is a very good explanation Marc..i was not able to understand the concept of equals and hashcode implementation so far.i referred lot of notes..now i am getting it..
thank you