Can hashCode() and == diverge without overriding hashCode - java

Given java Object#hashCode documentation snapshot :
As much as is reasonably practical, the hashCode method defined by
class Object does return distinct integers for distinct objects. (The
hashCode may or may not be implemented as some function of an object's
memory address at some point in time.)
How would we make this method return true without overriding the hashCode() method ?
boolean challenge(Object o1, Object o2) {
return o1 == o2 && o1.hashCode() != o2.hashCode();
}
Stated otherwise, make this method return true :
boolean makeMeReturnTrue(Object o1, Object o2) {
return o1 == o2 && System.identityHashCode(o1) != System.identityHashCode(o2);
}

You cannot.
If o1 == o2, then o1.hashCode() is certain to return the same value as o2.hashCode(), which will make the expression return false.
One of the properties of hashCode() is consistency, meaning that within the same program, the result of hashCode() on the same object should not change (and changing the return value is the only way to make the expression return true - but you can't get Object.equals to return incosistent values, so you would be forced to override hashCode to break the contract for yourself).

return o1 == o2 && o1.hashCode() != o2.hashCode();
The expression o1 == o2 tests o1 and o2 to see if they refer to the same object. Not two objects that compare equally, but the actual same object. So o1 == o2 will only be true if o1 and o2 refer to the same object.
Given that o1 and o2 must be the same object, the only way for o1.hashCode() != o2.hashCode() to be true would be if the relevant hashCode() method returned a different value each time it was called. For example, the expression could be true if hashCode() returned a random value each time it was called. That violates the expectation for hashCode(), but you could certainly write a non-conformant hashCode() method if you wanted to.

Well, its going to depend on actual implementation of hashCode() and equals() for the final Objects that get passed in. It looks like your class has an implementation where equality stands for "we contain the same data", but you seem to be hoping that the hash code implementation is based on the memory address or some other "unique to this instantiation" identifier so that something may not challenge itself.
You could always manage that identifier yourself, which would be safest (since the underlying implementation of hashCode() could change on a default version of a common data structure during a major Java version update for example), but it might be overkill.

Just download openJDK and modify the code as per your requirement. It'll work. But it'll work only in your own custom JDK that you have created by modifying OpenJDK. Use your custom JDK where you need to deploy your application.

Related

Compare two objects and add them in a Set [duplicate]

This question already has answers here:
Compare two objects with .equals() and == operator
(16 answers)
Closed 9 years ago.
I have two java objects that are instantiated from the same class.
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
If I set both of their properties to the exact same values and then verify that they are the same
if(myClass1 == myClass2){
// objects match
...
}
if(myClass1.equals(myClass2)){
// objects match
...
}
However, neither of these approaches return a true value. I have checked the properties of each and they match.
How do I compare these two objects to verify that they are identical?
You need to provide your own implementation of equals() in MyClass.
#Override
public boolean equals(Object other) {
if (!(other instanceof MyClass)) {
return false;
}
MyClass that = (MyClass) other;
// Custom equality check here.
return this.field1.equals(that.field1)
&& this.field2.equals(that.field2);
}
You should also override hashCode() if there's any chance of your objects being used in a hash table. A reasonable implementation would be to combine the hash codes of the object's fields with something like:
#Override
public int hashCode() {
int hashCode = 1;
hashCode = hashCode * 37 + this.field1.hashCode();
hashCode = hashCode * 37 + this.field2.hashCode();
return hashCode;
}
See this question for more details on implementing a hash function.
You need to Override equals and hashCode.
equals will compare the objects for equality according to the properties you need and hashCode is mandatory in order for your objects to be used correctly in Collections and Maps
You need to implement the equals() method in your MyClass.
The reason that == didn't work is this is checking that they refer to the same instance. Since you did new for each, each one is a different instance.
The reason that equals() didn't work is because you didn't implement it yourself yet. I believe it's default behavior is the same thing as ==.
Note that you should also implement hashcode() if you're going to implement equals() because a lot of java.util Collections expect that.
You have to correctly override method equals() from class Object
Edit: I think that my first response was misunderstood probably because I was not too precise. So I decided to to add more explanations.
Why do you have to override equals()? Well, because this is in the domain of a developer to decide what does it mean for two objects to be equal. Reference equality is not enough for most of the cases.
For example, imagine that you have a HashMap whose keys are of type Person. Each person has name and address. Now, you want to find detailed bean using the key. The problem is, that you usually are not able to create an instance with the same reference as the one in the map. What you do is to create another instance of class Person. Clearly, operator == will not work here and you have to use equals().
But now, we come to another problem. Let's imagine that your collection is very large and you want to execute a search. The naive implementation would compare your key object with every instance in a map using equals(). That, however, would be very expansive. And here comes the hashCode(). As others pointed out, hashcode is a single number that does not have to be unique. The important requirement is that whenever equals() gives true for two objects, hashCode() must return the same value for both of them. The inverse implication does not hold, which is a good thing, because hashcode separates our keys into kind of buckets. We have a small number of instances of class Person in a single bucket. When we execute a search, the algorithm can jump right away to a correct bucket and only now execute equals for each instance. The implementation for hashCode() therefore must distribute objects as evenly as possible across buckets.
There is one more point. Some collections require a proper implementation of a hashCode() method in classes that are used as keys not only for performance reasons. The examples are: HashSet and LinkedHashSet. If they don’t override hashCode(), the default Object
hashCode() method will allow multiple objects that you might consider "meaningfully
equal" to be added to your "no duplicates allowed" set.
Some of the collections that use hashCode()
HashSet
LinkedHashSet
HashMap
Have a look at those two classes from apache commons that will allow you to implement equals() and hashCode() easily
EqualsBuilder
HashCodeBuilder
1) == evaluates reference equality in this case
2) im not too sure about the equals, but why not simply overriding the compare method and plant it inside MyClass?

What's the relationship between equals and hashCode?

Question: if there are two objects o1 and o2 such that o1.equals(o2), what is java's standard convention about the relationship between o1.hashCode() == o2.hashCode()?
Answer: o1.hashCode() == o2.hashCode()
I don't know why..what i thought was since o1 and o2 are different objects, they shouldn't have the same hashCode. If what the question says were o1 == o2, then I would say they have the same hashCode since both o1 and o2 point to the same object.
Can anyone point out what I did wrong?
.equals is used to evaluate the value of an object. When objects are hashed, their numerical values on a systems level are used to produce a hash code (an integer, if you will). If the objects are the exact same (e.g. in terms of attributes), they will have the same numerical sequence and therefore hash to the same value.
Equals and Hashcode always go hand in hand. If o1 == o2, then they point to the same memory and hashcodes are trivially equal. However, one you implement Equals, you always have to make sure that when Equals returns true, Hashcode must return the same value.
Here are the official docs which set out the requirements/standards.

How to compare two java objects [duplicate]

This question already has answers here:
Compare two objects with .equals() and == operator
(16 answers)
Closed 9 years ago.
I have two java objects that are instantiated from the same class.
MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();
If I set both of their properties to the exact same values and then verify that they are the same
if(myClass1 == myClass2){
// objects match
...
}
if(myClass1.equals(myClass2)){
// objects match
...
}
However, neither of these approaches return a true value. I have checked the properties of each and they match.
How do I compare these two objects to verify that they are identical?
You need to provide your own implementation of equals() in MyClass.
#Override
public boolean equals(Object other) {
if (!(other instanceof MyClass)) {
return false;
}
MyClass that = (MyClass) other;
// Custom equality check here.
return this.field1.equals(that.field1)
&& this.field2.equals(that.field2);
}
You should also override hashCode() if there's any chance of your objects being used in a hash table. A reasonable implementation would be to combine the hash codes of the object's fields with something like:
#Override
public int hashCode() {
int hashCode = 1;
hashCode = hashCode * 37 + this.field1.hashCode();
hashCode = hashCode * 37 + this.field2.hashCode();
return hashCode;
}
See this question for more details on implementing a hash function.
You need to Override equals and hashCode.
equals will compare the objects for equality according to the properties you need and hashCode is mandatory in order for your objects to be used correctly in Collections and Maps
You need to implement the equals() method in your MyClass.
The reason that == didn't work is this is checking that they refer to the same instance. Since you did new for each, each one is a different instance.
The reason that equals() didn't work is because you didn't implement it yourself yet. I believe it's default behavior is the same thing as ==.
Note that you should also implement hashcode() if you're going to implement equals() because a lot of java.util Collections expect that.
You have to correctly override method equals() from class Object
Edit: I think that my first response was misunderstood probably because I was not too precise. So I decided to to add more explanations.
Why do you have to override equals()? Well, because this is in the domain of a developer to decide what does it mean for two objects to be equal. Reference equality is not enough for most of the cases.
For example, imagine that you have a HashMap whose keys are of type Person. Each person has name and address. Now, you want to find detailed bean using the key. The problem is, that you usually are not able to create an instance with the same reference as the one in the map. What you do is to create another instance of class Person. Clearly, operator == will not work here and you have to use equals().
But now, we come to another problem. Let's imagine that your collection is very large and you want to execute a search. The naive implementation would compare your key object with every instance in a map using equals(). That, however, would be very expansive. And here comes the hashCode(). As others pointed out, hashcode is a single number that does not have to be unique. The important requirement is that whenever equals() gives true for two objects, hashCode() must return the same value for both of them. The inverse implication does not hold, which is a good thing, because hashcode separates our keys into kind of buckets. We have a small number of instances of class Person in a single bucket. When we execute a search, the algorithm can jump right away to a correct bucket and only now execute equals for each instance. The implementation for hashCode() therefore must distribute objects as evenly as possible across buckets.
There is one more point. Some collections require a proper implementation of a hashCode() method in classes that are used as keys not only for performance reasons. The examples are: HashSet and LinkedHashSet. If they don’t override hashCode(), the default Object
hashCode() method will allow multiple objects that you might consider "meaningfully
equal" to be added to your "no duplicates allowed" set.
Some of the collections that use hashCode()
HashSet
LinkedHashSet
HashMap
Have a look at those two classes from apache commons that will allow you to implement equals() and hashCode() easily
EqualsBuilder
HashCodeBuilder
1) == evaluates reference equality in this case
2) im not too sure about the equals, but why not simply overriding the compare method and plant it inside MyClass?

Does it matter if two hashCodes are equal, even if the two objects aren't from the same type?

Let's say I have two types A and B that both have a unique id field, here is how I usually implement the equals() and hashCode() methods:
#Override
public boolean equals(Object obj) {
return obj instanceof ThisType && obj.hashCode() == hashCode();
}
#Override
public int hashCode() {
return Arrays.hashCode(new Object[] { id });
}
In that case, given that A and B both have a 1-arg constructor to set their respective id field,
new A(1).equals(new A(1)) // prints true as expected,
new A(1).equals(new A(2)) // prints false as expected,
new A(1).equals(new B(1)) // prints false as expected.
But also,
new A(1).hashCode() == new B(1).hashCode() // prints true.
I wonder if it matters if two hashCodes are equal, even if the two objects aren't from the same type? Could hashCode() be used somewhere else than in equals()? If yes, to what purpose?
I thought about implementing the two methods as follow:
#Override
public boolean equals(Object obj) {
return obj != null && obj.hashCode() == hashCode();
}
#Override
public int hashCode() {
return Arrays.hashCode(new Object[] { getClass(), id });
}
Adding the class to the hashCode generation would solve this potential problem. What do you think? Is it necessary?
For objects of different classes the same hashCode() does not matter. The hashCode() only says that the objects are possibly the same. If e.g. HashSet encounters the same hashCode() it will test for equality with equals().
The rule is simple:
A.equals(B) implies B.hashcode() == A.hashcode()
B.hashcode() != A.hashcode() implies !A.equals(B)
There should be no other relations between the two. If you use hashcode() inside equals(), you should have a warning.
Hashcode is definitely not used in equals; it is used by collections based on the data structure called a hash table. It is always OK from the correctness standpoint for two hashcodes to equal each other; this is called a hash collision, it is unavoidable in the general case, and the only consequence is weaker performance.
Nothing wrong with two different objects (even of the same type) to have the equal hash code, but your second variant of equals() looks odd to me. It will work only if you can guarantee that your objects will be compared only to the objects of the same type.
Could hashCode() be used somewhere else than in equals()?
This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable. from javadoc
Also
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
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.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
Not that, when A extends B, or B extends A, then your equals method is faulty, since:
a.equals(b) != b.equals(a)
if a and b happen to have the same hash code.

How do sets differentiate between objects?

How does a set differentiate between objects in both Java and C++? Or do sets not differentiate them at all?
Take these for example:
C++
std::set<A> aset;
A a(1, 2); // Assume A has only two elements, and this constructor sets them both
aset.insert(a);
A a2(1, 2); // This would initialise a `A' object to the same values as `a', but a different object
aset.count(a2); // Would this return 1 or 0?
Java
set<A> aset;
A a = new A(1, 2); // Assume A has only two elements, and this constructor sets them both
aset.add(a);
A a2 = new A(1, 2); // This would initialise a `A' object to the same values as `a', but a different object
aset.contains(a2); // Would this return true or false?
In C++ the set depends on operator<() being defined for the class A, or that you supply a comparison object providing strict weak ordering to the set.
For Java it depends on the equals, hashcode contract.
For the Java part,
The method in charge of determining whether two objects are equal is:
public boolean equals(Object other)
Not to be confused with
public int hashCode()
Whose contract states that two equals objects must return the same number, but two objects that returned the same number may be, but are not necessarily, equal.
The default implementation for the equals method is equality by memory address, therefor if class A did not override the equals method the contains method will return false.
To have the set.contains(a2) method return true you must override the equals and hashCode method to comply as so:
public boolean equals(Object other) {
return other instanceof A && ((A) other).elem1 = this.elem1 && ((A) other).elem2 = this.elem2;
}
public int hashCode() {
return elem1 * 31 + elem2;
}
The hashCode is required (assuming you're using a HashSet) for the set to identify where in the internal representation of the set the object may be (i.e. where to look for it).
Search for HashSet\HashMap to understand the internal representation if you're interested.
As for the C++ part, If I remember correctly it depends on the correct operator overloading, but my C++ is rusty at best.
EDIT: I noticed you specifically asked about sets so I'll elaborate a bit more on how that:
While the equals method is what determines equality between two objects, some preliminary steps in the set implementation used (e.g. HashSet or TreeSet) might relay on something extra:
For example, the HashSet uses the hashCode() function to find the internal location the item might be in, so if A did not override/correctly implement the hashCode() function, the set.contains(a2) may return true or false (for default implementation it's non deterministic - depends on memory location and the current capacity of the set).
For a TreeSet internal implementation to correctly find items within it either the items contained must be implement the Comparable interface properly or the TreeSet itself must be supplied with a Comparator instance implemented properly.
for C++, according to set::insert in C++ Reference
Because set containers do not allow for duplicate values, the
insertion operation checks for each
element inserted whether another
element exists already in the
container with the same value, if so,
the element is not inserted and -if
the function returns a value- an
iterator to it is returned
.
They check for the values, unlike Java, which only checks for the address instead.
In Java at least, comparison is done on a hash code, which by default is created from the location of the object in memory. So in the Java part of the question, aset.contains(a2); would return false, as a2 points to a different part of the memory to a.
I'm afraid I can't comment on how C++ works!
Java calls the object's equals method, which, if you haven't overridden it, is the same as calling Object.hashCode().

Categories

Resources