Does Hashcode equality imply refer reference based equality? - java

I read that to use equals() method in java we also have to override the hashcode() method and that the equal (logically) objects should have eual hashcodes, but doesn't that imply reference based equality! Here is my code for overridden equals() method, how should I override hashcode method for this:
#Override
public boolean equals(Object o)
{
if (!(o instanceof dummy))
return false;
dummy p = (dummy) o;
return (p.getName() == this.getName() && p.getId() == this.getId() && p.getPassword() == this.getPassword());
}
I just trying to learn how it works, so there are only three fields, namely name , id and password , and just trying to compare two objects that I define in the main() thats all! I also need to know if it is always necessary to override hashcode() method along with equals() method?

Hashcode equality does not imply anything. However, hashcode inequality should imply that equals will yield false, and any two items that are equal should always have the same hashcode.
For this reason, it is always wise to override hashcode with equals, because a number of data structures rely on it.

Even though failure to override hashCode() will only break usage of your class in HashSet, HashMap, and other hashCode dependent structures, you should still override hashCode() to maintain the contract described by Object.
The general strategy of most hashCode() implementations is to combine the hash codes of the fields used to determine equality. In your case, a reasonable hashCode() may look something like this:
public int hashCode(){
return this.getName().hashCode() ^ this.getId() ^ this.getPassword().hashCode();
}

You need to override hashCode() when you override equals(). Merely using equals() is not enough to require you to override hashCode().

In your code, you aren't actually comparing your fields' values. Use equals() instead of == to make your implementation of equal correct.
return (p.getName().equals(this.getName()) && ...
(Note that the above code can cause null reference exceptions if getName() returns null: you may want to use a utility class as described here)
And yes hashCode() would be called when you use some hashing data structure like HashMap,HashSet
You must override hashCode() in every
class that overrides equals(). Failure
to do so will result in a violation of
the general contract for
Object.hashCode(), which will prevent
your class from functioning properly
in conjunction with all hash-based
collections, including HashMap,
HashSet, and Hashtable.
from Effective Java, by Joshua Bloch
Also See
overriding-equals-and-hashcode-in-java
hashcode-and-equals
Nice article on equals() & hashCode()

The idea with hashCode() is that it is a unique representation of your object in a given space. Data structures that hold objects use hash codes to determine where to place objects. In Java, a HashSet for example uses the hash code of an object to determine which bucket that objects lies in, and then for all objects in that bucket, it uses equals() to determine whether it is a match.
If you don't override hashCode(), but do override equals(), then you will get to a point where you consider 2 objects to be equal, but Java collections don't see it the same way. This will lead to a lot of strange behaviour.

Related

why should I override equals and hashcode method for following scnerio

why I need to override for direct access of value in Hash map.That is if insert data into hashmap as follow HashMap,I could get value by giving the Key as Integer ,would get Object as Value.In this case is it necessary to Override equals() and hashCode() method?Please give suggestion.
No, you don't need to override anything to use an object as a value in a HashMap.
Only keys need to have a working hashCode().
However, you need to implement these two methods (technically only equals, but these two are a set, really) if you want to use things like Map#containsValue, List#indexOf or Collection#contains (and these should not just be using reference identity).
hashCode() is used to search for a specific elem when you want to retrieve it from a hashTable. hashCode() doesn't have to be distinct. in fact, you could just return the same integer for all your instance, but then, elems are stored in a list instead of a hashTable, and will cause a performance problem.
By default implementation of hashCode() (which is the implementation of Object for subClass to extents from )of JVM returns a integer according to the memory address of the object, so this should be enough, but this implement was not required by the JVM standard.
By default(Class object), implementation of equals() will return true and only return true when they have same reference , ie obj1 == obj2. read this
keep in mind that:
equal objects must have same hashCode()
those have same hashCode() are not required to be equal to each other.
I think override of hashCode() is not needed in most situations(not extends from other Class), cause modern JVMs has done
pretty good job for you.
So conclusion is:
if your super class have overwrite the hashCode() and equals() method, then you should override them, or at least take a look at the implementation, and decide whether you should override them.

Does singleton means hashcode always return the same?

I have two objects, o1 and o2 from the same class.
If o1.hashcode() == o2.hashcode(), can I tell they are the same object?
Beside o1==o2, is there any other way to tell the singleton.
If you have a single instance of the class, the == and the equals comparison will always return true.
However, the hashcode can be equal for different objects, so an equality is not guaranteed just by having equal hashcodes.
Here is a nice explanation of the hashcode and equals contracts.
Checking the equality is not sufficient to be sure that you have a singleton, only that the instances are considered equal.
If you want to have a single instance of a java class, it may be better to make use of static members and methods.
Here, several approaches to singletons are demonstrated.
EDIT: as emory pointed out - you could in fact override equals to return something random and thus violate the required reflexivity (x.equals(x) == true). As you cannot override operators in java, == is the only reliable way to determine identical objects.
No, different objects can have the same hashCode():
"hypoplankton".hashCode()
"unheavenly" .hashCode()
both return the same 427589249 hash value, while they are clearly not equal.
Your question (from the title) seems to be "will hashCode() always return the same value for the same object"... the answer is no.
The implementation is free to return anything, although to be well behaved it should return the same for the same object. For example, this is a valid, albeit poor, implementation:
#Override
public int hashCode() {
return (int) (Math.random() * Integer.MAX_VALUE);
}
The general contract for the hashCode is described below (Effective Java, page. 92). The 3rd item means that the hashCode() results do not need to be unique when called on unequal objects.
Within the same program, the result of hashCode() must not change
If equals() returns true when called with two objects, calling hashCode() on each of those objects must return the same result
If equals() returns false when called with two objects, calling hashCode() on each of those objects does not have to return a different result

Java Set collection - override equals method

Is there any way to override the the equals method used by a Set datatype? I wrote a custom equals method for a class called Fee. Now I have a LnkedList of Fee and I want to ensure that there are no duplicated entries. Thus I am considering using a Set insted of a LinkedList, but the criteria for deciding if two fees are equal resides in the overriden equals method in the Fee class.
If using a LinkedList, I will have to iterate over every list item and call the overriden equals method in the Fee class with the remaining entries as a parameter. Just reading this alone sounds like too much processing and will add to computational complexity.
Can I use Set with an overridden equals method? Should I?
As Jeff Foster said:
The Set.equals() method is only used to compare two sets for equality.
You can use a Set to get rid of the duplicate entries, but beware: HashSet doesn't use the equals() methods of its containing objects to determine equality.
A HashSet carries an internal HashMap with <Integer(HashCode), Object> entries and uses equals() as well as the equals method of the HashCode to determine equality.
One way to solve the issue is to override hashCode() in the Class that you put in the Set, so that it represents your equals() criteria
For Example:
class Fee {
String name;
public boolean equals(Object o) {
return (o instanceof Fee) && ((Fee)o.getName()).equals(this.getName());
}
public int hashCode() {
return name.hashCode();
}
}
You can and should use a Set to hold an object type with an overridden equals method, but you may need to override hashCode() too. Equal objects must have equal hash codes.
For example:
public Fee{
public String fi;
public String fo;
public int hashCode(){
return fi.hashCode() ^ fo.hashCode();
}
public boolean equals(Object obj){
return fi.equals(obj.fi) && fo.equals(obj.fo);
}
}
(With null checks as necessary, of course.)
Sets often use hashCode() to optimize performance, and will misbehave if your hashCode method is broken. For example, HashSet uses an internal HashMap.
If you check the source code of HashMap, you'll see it depends on both the hashCode() and the equals() methods of the elements to determine equality:
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
If the hash is not generated correctly, your equals method may never get called.
To make your set faster, you should generate distinct hash codes for objects that are not equal, wherever possible.
Set uses the equals method of the object added to the set. The JavaDoc states
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.
The Set.equals() method is only used to compare two sets for equality. It's never used as part of adding/remove items from the set.
One solution would be to use a TreeSet with a Comparator.
From the documentation:
TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal.
This approach would be much faster than using a LinkedList, but a bit slower than a HashSet (ln(n) vs n).
It's worth noting a one side effect of using TreeSet would be that your set is sorted.
There are PredicatedList or PredicatedSet in Apache Commons Collection

Java hashCode doubt

I have this program:
import java.util.*;
public class test {
private String s;
public test(String s) { this.s = s; }
public static void main(String[] args) {
HashSet<Object> hs = new HashSet<Object>();
test ws1 = new test("foo");
test ws2 = new test("foo");
String s1 = new String("foo");
String s2 = new String("foo");
hs.add(ws1);
hs.add(ws2);
hs.add(s1);
hs.add(s2); // removing this line also gives same output.
System.out.println(hs.size());
}
}
Note that this is not a homework. We were asked this question on our quiz earlier today. I know the answers but trying to understand why it is so.
The above program gives 3 as output.
Can anyone please explain why that is?
I think (not sure):
The java.lang.String class overrides the hashCode method from java.lang.Object. So the String objects with value "foo" will be treated as duplicates. The test class does not override the hashCode method and ends up using the java.lang.Object version and this version always returns a different hashcode for every object, so the two test objects being added are treated as different.
In this case it's not about hashCode() but is about equals() method. HashSet is still Set, which has semantic of not allowing duplicates. Duplicates are checked for using equals() method which in case of String will return true
However for your test class equals() method is not defined and it will use the default implementation from Object which will return true only when both references are to the same instance.
Method hashCode() is used not to check if objects should be treated as same but as a way to distribute them in collections based on hash functions. It's absolutely possible that for two objects this method will return same value while equals() will return false.
P.S. hashCode implementation of Object doesn't guarantee uniqueness of values. It's easy to check using simple loop.
Hashcode is used to narrow down the search result. When we try to insert any key in HashMap first it checks whether any other object present with same hashcode and if yes then it checks for the equals() method. If two objects are same then HashMap will not add that key instead it will replace the old value by new one.
In fact, it is not about overriding the hashcode(), it is about equals method. Set does not allow duplicates. A duplicate is the one where the objects are logically equal.
For verifying you can try with
System.out.println(ws1.equals(ws2));
System.out.println(s1.equals(s2));
If the objects are equal, only one will be accepted by a set.
Below are few (well quite many) bullets refarding the equals and hashcode from my preparations to SCJP.
Hope it helps:
equals(), hashCode(), and toString() are public.
Override toString() so that System.out.println() or other methods can see something useful, like your object's state.
Use == to determine if two reference variables refer to the same object.
Use equals() to determine if two objects are meaningfully equivalent.
If you don't override equals(), your objects won't be useful hashing keys.
If you don't override equals(), different objects can't be considered equal.
Strings and wrappers override equals() and make good hashing keys.
When overriding equals(), use the instanceof operator to be sure you're evaluating an appropriate class.
When overriding equals(), compare the objects' significant attributes.
Highlights of the equals() contract:
a. Reflexive: x.equals(x) is true.
b. Symmetric: If x.equals(y) is true, then y.equals(x) must be true.
c. Transitive: If x.equals(y) is true, and y.equals(z) is true, then z.equals(x) is true.
d. Consistent: Multiple calls to x.equals(y) will return the same result.
e. Null: If x is not null, then x.equals(null) is false.
f. If x.equals(y) is true, then x.hashCode() == y.hashCode() is true.
If you override equals(), override hashCode().
HashMap, HashSet, Hashtable, LinkedHashMap, & LinkedHashSet use hashing.
An appropriate hashCode() override sticks to the hashCode() contract.
An efficient hashCode() override distributes keys evenly across its buckets.
An overridden equals() must be at least as precise as its hashCode() mate.
To reiterate: if two objects are equal, their hashcodes must be equal.
It's legal for a hashCode() method to return the same value for all instances (although in practice it's very inefficient).
In addition if you implement equals and hashcode the transient fields (if any) must be treated properly.
The Commons have nice implementation for EqualsBuilder and HashcodeBuilder. They are available in Coomons Lang
http://commons.apache.org/lang/
I use them whenevr I need to implement the equals and the hashcode.

Can you explain this Java hash map key collision?

I have a HashMap and is used in the following way:
HashMap<SomeInterface, UniqueObject> m_map;
UniqueObject getUniqueObject(SomeInterface keyObject)
{
if (m_map.containsKey(keyObject))
{
return m_map.get(keyObject);
}
else
{
return makeUniqueObjectFor(keyObject);
}
}
My issue is that I'm seeing multiple objects of different classes matching the same key on m_map.containsKey(keyObject).
So here are my questions:
Is this possible? The Map interface says it uses equals() to compare if the key is not null. I haven't overridden equals() in any of my SomeInterface classes. Does this mean the equals method can be wrong?
If the above is true, how do I get HashMap to only return true on equals() if they are in fact the same object and not a copy? Is this possible by saying if (object1 == object2)? I was told early on in Java development that I should avoid doing that, but I never found out when it should be used.
Thanks in advance. :)
I strongly suspect you've misdiagnosed the issue. If you aren't overriding equals anywhere (and you're not subclassing anything else that overrides equals) then you should indeed have "identity" behaviour.
I would be shocked to hear that this was not the case, to be honest.
If you can product a short but complete program which demonstrates the problem, that would make it easier to look into - but for the moment, I'd definitely double-check your suspicions about seeing different objects being treated as equal keys.
The default implementation of equals() is done in java.lang.Object:
public boolean equals(Object obj) {
return (this == obj);
}
Other method hashCode(); by default returns some kind of reference to the object. I.e. both are unique by default. Equals returns true only for the same object, hashCode() is different for every object.
This is exactly what can create some kind of multiple entries. You can create 2 instances of your class. From your point of view they are equal because they contain identical data. But they are different. So, if you are using these objects as keys of map you are producing 2 entries. If you want to avoid this implement equals and hashCode for your class.
This implementation sometimes is very verbose. HashCodeBuilder and EqualsBuilder from Jakarta project may help you. Here is an example:
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
#Override
public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
You need to ensure that your .equals() and your .hashCode() methods are implemented for all objects that you want to store in the HashMap. To not have that invites all sorts of problems.
You must implement the equals() and hashCode() methods of the objects that you use as the keys in the HashMap.
Note that HashMap not only uses equals(), it also uses hashCode(). Your hashCode() method must be implemented correctly to match the implementation of the equals() method. If the implementation of these methods don't match, you can get unpredictable problems.
See the description of equals() and hashCode() in the API documentation of class Object for the detailed requirements.
FYI you can have IDE's such as Eclipse generate the hashCode & equals methods for you. They'll probably do a better job than if you try to hand-code them yourself.

Categories