Equals with multiple values Java - java

I've made a Java class in which I simulate a Polynome (it contains an ArrayList<Pairs>, each pair has its own coefficient and exponent). But now I like to compare two Polynome's with the equals() method (with an Object).
I know I can't say that this == that because this will only compare the Polynome references. SO now I wondered if there's an easy way to compare both Polynome's values, or do I just have to check the first Pair of the first Polynome to the first Pair of the second Polynome etc.?

You have to override the equals() method of your Pair class to return true if and only if both the coefficient and the exponent are equal.
You should also override the hashCode() method if you override equals(). Although strictly speaking this isn't mandatory while you're using ArrayLists, it is good practice to always override equals() and hashCode() together.
Also note that because you're using a List, where the order of elements matters, x3+2x-1 won't be equal to 2x-1+x3, which is probably not what you want to see. You should store your Pair objects in a Set instead, as their equals() doesn't rely on the order in which you added the elements to them.

You have to override equals and check each and every Monomial in the Polynomial collection.
Hint: I'd have two classes - Monomial, with its own equals and hashCode, and a separate Polynomial, which would have a Set of Monomials and its own equals and hashCode.

Related

Is it necessary to override equals and hashCode methods in a class if I use the objects of class to insert in a TreeSet only? [duplicate]

I have a quick question about TreeSet collections and hashCode methods. I have a TreeSet and I'm adding objects to it, before I add an object, I check to see if it exists in the TreeSet using the contains method.
I have 2 distinct objects, each of which produce a distinct hashCode using my implementation of the hashCode method, example below:
public int hashCode()
{
int hash = 7;
hash = hash * 31 + anAttribute.hashCode();
hash = hash * 31 + anotherAttribute.hashCode();
hash = hash * 31 + yetAnotherAttribute.hashCode();
return hash;
}
The hashCodes for a particular run are: 76126352 and 76126353 (the objects only differ by one digit in one attribute).
The contains method is returning true for these objects, even though the hashCodes are different. Any ideas why? This is really confusing and help would really be appreciated.
TreeSet does not use hashCode at all. It uses either compareTo or the Comparator you passed to the constructor. This is used by methods like contains to find objects in the set.
So the answer to your question is that your compareTo method or your Comparator are defined so that the two objects in question are considered equal.
From the javadocs:
a 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.
From Java Doc:
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.
Means: the objects you use for hashing are not equal.
You need to read Joshua Bloch's "Effective Java" chapter 3. It explains the equals contract and how to properly override equals, hashCode, and compareTo.
You don't need to checked if it is contained, because the insert() basically does the same operation (i.e. searching the proper position) on its way to the insertion point. If the object can't be inserted (i.e., the object is already contained), insert returns false.

Why can't I just compare the hashCode of two objects in order to find out if they are equal or not?

Why do the equals methods implemented by Eclipse compare each value, wouldn't it be simpler to just compare the hashCodes of both objects?
From what I know:
hashCode always generates the same hash for the same input
So if two objects are equal, they should have the same hash
If objects that are equal have the same hash, I can just check the hash in order to determine of objects are equal or not
edit: Related question, why does one always implement the hashCode when equals is implemented, if the hashCode isn't actually needed for equals?
hashCode always generates the same hash for the same input
Correct.
So if two objects are equal, they should have the same hash
Correct.
If objects that are equal have the same hash, I can just check the hash in order to determine of objects are equal or not
Non sequitur. Objects that are unequal can also have the same hashcode. That is the purpose of a hashcode.
Related question, why does one always implement the hashCode when equals is implemented, if the hashCode isn't actually needed for equals?
Because it is needed for hashing, in HashMap, HashSet, and friends. If you think your object will never be so used, don't override it, and good luck with that.
To complement #EJP's answer, here is a perfectly valid, although useless, implementation of .hashCode():
#Override
public int hashCode()
{
return 42; // The Answer
}
Putting this in very simple terms: while every squirrel is an animal, not every animal is a squirrel. The hashCode is usually used for quick lookup - it should be efficient and it should distribute data uniformly across a lookup table - see here. But a hash function can generate collisions, which is why it shouldn't be used as a means of verifying object equality.
It's all very much dependent on the implementation of hashCode - as you can also see in fge's answer.
As to why it usually needs to be reimplemented when you override equals: they are both used when storing and retrieving objects from collections (for example a HashMap). The hashCode determines the place in the map where the object will be inserted, while equals is used to identify the object inside a collision bucket.

Questions about contains method in Hash Set

I am a high school student so I apologize for the terms I may misuse.
So I am making a slide puzzle game and working on the AI part. So I have a constructor that construct board and assign its hashcode such as 123456780. In my A* algorithm, I compare if the board that I generate (to find the solution) is already in the hashset. So I use contains method for it right? but how does the contains method works to check if the two boards are identical?.
public Board()
{
board = new int [3][3];
setPieces (board);
hashCode = generateHashCode ();
}
This is one of my constructor. In my board object, I have 2D array and the hashcode. But I wonder again, if the built-in contains method in Hash Set compare two boards hashcode. Or I need to write one.
Also, when I assign the hash code to a board, I should do it in my constructor right?
Thanks you
As you've discovered, you need to return a hashcode for your object in the overridden hashCode() method.
You can either compute a hashcode in that method, or compute it in the ctor and store it in a field, then return the field in the method override.
Any collection that uses the 'Hash' prefix has all objects contained within the collection stored in groups by their hashcode. So when you call a method like contains() the collection loops through each hashcode group and checks whether the hashcode of the object you parsed in matches the group. When a match is found, the objects within that hashcode group are checked using the equals() method of the stored object until an Object's equals() method returns true.
If you do not override the hashcode() method, then each Object subclass is given a more or less unique hashcode by the Object class implementation of the hashcode() method. This can cause some problems if you have already overridden the equals() method, because if two objects are considered equal the contains() method might still not find it if the hashcodes do not match.
The hashcode contract:
When implementing hashcode() the Java Object API has laid out a contract or a set of specifications on how you should implement the hashcode method. And they are;
If hashcode() is run on an object multiple times, it must always return the same number.
If two objects are considered equal by the equals() method then their hashcode() methods must return the same value.
If two objects have the same hashcode, they do not have to be considered equal by their equals() methods.
References:
The hashcode contract.
Implementing hashcode.

Java Set can not distinguish different objects

I have one class Human, which contains two fields, age(int), and name(String). With eclipse, I override the hashCode() and equals() method with these two fields. I also create a Comparator based on the age field.
Now, I create a TreeSet object with the Comparator of age, and also two instances (with different fields values) of Human class. Then I add these two objects into the set, however, there are always only one object in the set.
For understanding the problem, I print out the hash value of these two objects, and find them are different. Then, I test their equals() method, it does output false when I compare two instances with different field values. So now, I cannot figure out why the TreeSet can't handle (differentiate) the problem. Can anyone give me some help ? Thanks a lot !
TreeSet doesn't use hashCode() and equals() at all. It uses the comparator you pass as argument (or the compareTo() method of the objects if they are Comparable and you don't provide a comparator). Two objects are considered equal by a TreeSet if compare() (orcompareTo()) returns 0 when comparing these two objects.
So if your comparator only compares the age of humans, all the humans with the same age will be considered equal. If you want humans to be considered equal when they have the same age and name, then the comparator should compare by age, and then compare by name if the age comparison returns 0.
From the documentation
This is so because the Set interface is defined in terms of the equals
operation, but a 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. The behavior of a set is well-defined even if its ordering is
inconsistent with equals; it just fails to obey the general contract
of the Set interface.

Equal Objects must have equal hashcodes?

Equal Objects must have equal hashcodes. As per my understanding this statement is valid when we have intention of using object in hashbased datastuctures. This is one of contract for hashcode and equals method in java docs. I explored the reason why this is said and looked in the implementation of hashtable and found out below code in put method
if ((e.hash == hash) && e.key.equals(key))
So I got it, contract came from condition e.hash == hash above. I further tried to explore why java is checking hashcode when comparing two objects for equality. So here is my understaing
If two equal object have equal hascodes then they can be stored in the same bucket and this will be good in terms of look up in single bucket only
Its better to check hashcode then actually calling equals method because hascode method is less costly than equals method, because here we just have to compare int value where in equals method may be invloving object field comparison. So hashcode method providing one extra filter.
Please correct me if both above reasons are valid?
Correct, just a small correction - if two unequal objects have the same hashcode.
Not exactly, It's better to check it first, as a filter for the non-equal, but if you want to make sure the objects are equal, you should call equals()
You got it wrong. equals just returns a boolean value (two possible values), and needs another object to compare against. hashCode returns an int (2^32 possible values), and only needs the object to be called.
The HashMap tries to distribute all the objects it holds among buckets. When put is called on the map, it has to decide which bucket it will use for the given object. It thus uses hashCode (modulo the number of buckets) to decide which bucket to use. Then, once the bucket is found, it has to check whether the key is already in the map or not. To do this, it compares every object in the bucket with the object to put in the map. And to do this, it uses equals. If the object isn't found, it adds it in the bucket.
hashCode isn't used because it's faster than equals. It's used because it allows distributing keys among a set of buckets. And it's much faster to compute the hashCode once and compare the object with (hopefully) 0, one or two objects in the same bucket that to compare the object with the thousands of objects already stored in the map.
" I further tried to Exlpore why java is checking Hashcode when comparing two objects for equality". Put method is not just checking for equality, it is trying to first narrow down the bucket and then use the equals. That is why we need to combine HashCode with Equals in case of bucketed collections.
But if your sole intention is to just check equality between two objects, you will never need a hashcode method.
Obj1.equals(Obj2) will never use the hashcode method by default.
Its a general type of contract so that when we store the objects inside a hashing based data structure, then we should always consistently put or get the same object to and from the hashtable.
Its a contract which we have created to be followed such that the entry/put processes occur smoothly.

Categories