Java equals and hashmaps problem - java

So I'm learning Java and I'm trying to understand equals, but I really don't understand it. So my question is: how does equals works?
Thanks

equals is a method you use to discover if two given objects are the same. The default implementation of equals for an object is: They are the same if they have the exact same reference.
Sometimes, you don't want this. Say you have a ComplexNumber class, and two instances with value 1+i. You don't want them not to be equal just because they are different instances. In essence, they represent the same number. In this case, you should override equals to make sure it behaves as intended.
HashMaps use info from equals to know if the key you passed is already there.
From Effective Java book:
Always override hashcode when you
override equals
I'd also add to that: specially if you're using a Hashmap =)
Hashmaps uses also hashcode() to search faster for the keys, and the result for hashcode() must be consistent with the equals result. In other words, if x.equals(y), then x.hashcode() == y.hashcode() (or you may have undefined behavior for your hashmap). You may have x and y with x.hashcode() == y.hashcode() and !x.equals(y)
If you want a more specific answer, please make a more specific question =).

The equals method will compare values for equality.
the method equals is defined in the object class so which means that every other class can use this method to compare how it works: it will first check if its referring to its self then the haschode's of the object and if those are equal if so, it will then check each field in that object against the fields of the object you are comaparing to why you might ask co's the haschode could be the same but it can still contain other value's in the fields the odds are low but its needed to compare more in depth then.

equals() means "meaningfully equivalent." It's not the same as ==, which means "these are the same object." All classes have the equals() method, inheirited from the Object class. For example, say you write a Car class that stores make, model and owner:
Car carOne = new Car("Buick", "LeSabre", "John Doe");
Car carTwo = carOne;
Here, equals() and == will both return true, because both references point to the same car. But, for
Car carOne = new Car("Buick", "LeSabre", "John Doe");
Car carTwo = new Car("Buick", "LeSabre", "John Doe");
there are two distinct objects, so == returns false. However, since both cars are Buick LeSabres owned by John Doe, your equals() should be written return true (assuming for this example that nobody owns more than one car of the same type).
Also, as Samuel pointed out, if you override equals(), you should also override hashCode(); the reasons for that are outside the scope of this question, and well-documented elsewhere.

Related

If the hashcode() creates hashcode based on the address of the object, how can two different objects with same contents create the same hashcode?

When you read the description of hashCode() in the Object class, it says that
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.
I've read an article and it says that an object's hashcode() can provide different integer values if it runs in different environments even though their content is the same.
It does not happen with String class's hashcode() because the String class's hashcode() creates integer value based on the content of the object. The same content always creates the same hash value.
However, it happens if the hash value of the object is calculated based on its address in the memory. And the author of the article says that the Object class calculates the hash value of the object based on its address in the memory.
In the example below, the objects, p1 and p2 have the same content so equals() on them returns true.
However, how come these two objects return the same hash value when their memory addresses are different?
Here is the example code: main()
Person p1 = new Person2("David", 10);
Person p2 = new Person2("David", 10);
boolean b = p1.equals(p2);
int hashCode1 = p1.hashCode();
int hashCode2 = p2.hashCode();
Here is the overriden hashcode()
public int hashCode(){
return Objects.hash(name, age);
}
Is the article's content wrong?
If there is a hashCode() that calculates a hash value based on the instance's address what is the purpose of them?
Also, if it really exists, it violates the condition that Object class's hashCode() specifies. How should we use the hashCode() then?
I think you have misunderstood this statement:
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.
The word “must” means that you, the programmer, are required to write a hashCode() method which always produces the same hashCode value for two objects which are equal to each other according to their equals(Object) method.
If you don’t, you have written a broken object that will not work with any class that uses hash codes, particularly unsorted Sets and Maps.
I've read an article and it says that an object's hashcode() can provide different integer values if it runs in different environments even though their content is the same.
Yes, hashCode() can provide different values in different runtimes, for a class which does not override the hashCode() method.
… how come these two objects return the same hash value when their memory addresses are different?
Because you told them to. You overrode the hashCode() method.
If there is a hashCode() that calculates a hash value based on the instance's address what is the purpose of them?
It doesn’t have a lot of use. That’s why programmers are strongly recommended to override the method, unless they don’t care about object identity.
Also, if it really exists, it violates the condition that Object class's hashCode() specifies. How should we use the hashCode() then?
No it does not. The contract states:
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.
As long as the hashCode method defined in the Object class returns the same value for the duration of the Java runtime, it is compliant.
The contract also says:
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.
Two objects whose equals method reports that they are effectively equal must return the same hashCode. Any instance of the Object class whose type is not a subclass of Object is only equal to itself and cannot be equal to any other object, so any value it returns is valid, as long as it is consistent throughout the life of the Java runtime.
The article is wrong, memory address is not involved (btw. the address can change during the lifecycle of objects, so it's abstracted away as a reference). You can look at the default hashCode as a method that returns a random integer, which is always the same for the same object.
Default equals (inherited from Object) works exactly like ==. Since there is a condition (required for classes like HashSet etc. to work) that states when a.equals(b) then a.hashCode == b.hashCode, then we need a default hashCode which only has to have one property: when we call it twice, it must return the same number.
The default hashCode exists exactly so that the condition you mention is upheld. The value returned is not important, it's only important that it never changes.
No p1 and p2 does not have the same content
If you do p1.equals(p2) that will be false, so not the same content.
If you want p1 and p2 to equal, you need to implement the equals methods from object, in a way that compare their content. And IF you implement the equals method, then you also MUST implement the hashCode method, so that if equals return true, then the objects have the same hashCode().
Here's the design decision every programmer needs to make for objects they define of (say) MyClass:
Do you want it to be possible for two different objects to be "equal"?
If you do, then firstly you have to implement MyClass.equals() so that it gives the correct notion of equality for your purposes. That's entirely in your hands.
Then you're supposed to implement hashCode such that, if A.equals(B), then A.hashCode() == B.hashCode(). You explicitly do not want to use Object.hashCode().
If you don't want different objects to ever be equal, then don't implement equals() or hashCode(), use the implementations that Object gives you. For Object A and Object B (different Objects, and not subclasses of Object), then it is never the case that A.equals(B), and so it's perfectly ok that A.hashCode() is never the same as B.hashCode().

Object equals method and hashcode Method

I'm revising for my upcoming exam and I've came across a question from a past paper that I'm unsure on.
The question is the following : Describe the equivalence relation that the Object equals method implements. What relationship must hold between the Object equals method and hasCode methods?
If this came up in the exam then I wouldn't be too sure how about answering this. I'll try and give it my best shot. Since the Object equals method is checking whether two objects are equal, the hashcode gives objects ascii values. If you have two objects that are the same it is possible that they can be given the same hascode since they're equal. The object equals method you are told whether they're equal whereas the hashcode method gives you a value which you can then use to compare with other hashcodes and find out whether they're the same or not. Also could have I of mentioned something about overriding methods ? I'm not if that could come into play in the answer.
My answer is probably completely wrong but the best I could think off :P
To the Java API Documentation! especially Object.hashCode
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 means that if the equal method returns true, hashCode must return the same value for both objects.
x.equals(y) == true => x.hashCode() == y.hashCode()
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 hash tables.
But! If the objects are not the same they may have the same hashCode()! (But it is not advised)
The requirements for the equals() method are well described, so i won't repeat them here.
The question is clearly answered in the descriptions of both the equals() method and the hashCode() method. Have a look at equals method description and hashCode method description.
Here is the relevant answer you might be looking for:
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
Note that it is generally necessary to override the hashCode method
whenever this method is overridden, so as to maintain the general
contract for the hashCode method, which states that equal objects must
have equal hash codes.
This the hashCode method description:
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.
Also, the hashCode method does not give the ASCII value of an object, merely an integer value that uniquely defines the object.

Do I need a equals and Hashcode method if my class implements comparable in Java?

I found this comment on can StringBuffer objects be keys in TreeSet in Java?
"There are 2 identifying strategies used with Maps in Java (more-or-less).
Hashing: An input "Foo" is converted into a best-as-possible attempt to generate a number that uniquely accesses an index into an array. (Purists, please don't abuse me, I am intentionally simplifying). This index is where your value is stored. There is the likely possibility that "Foo" and "Bar" actually generate the same index value meaning they would both be mapped to the same array position. Obviously this can't work and so that's where the "equals()" method comes in; it is used to disambiguate
Comparison: By using a comparative method you don't need this extra disambiguation step because comparison NEVER produces this collision in the first place. The only key that "Foo" is equal to is "Foo". A really good idea though is if you can is to define "equals()" as compareTo() == 0; for consistency sake. Not a requirement."
my question is as follows:
if my class implements comparable, then does it mean I dont have to override equals and hashcode method for using my objects as keys in Hash collections. eg
class Person implements Comparable<Person> {
int id;
String name;
public Person(int id, String name) {
this.id=id;
this.name=name;
}
public int compareTo(Person other) {
return this.id-other.id;
}
}
Now, can I use my Person objects in Hashable collections?
The article you brough is talking on TreeSet. a tree set is a tree with each node has a place defined by it's value in compare to the other values already in the tree.
a hashTable stores key/value pairs in a hash table. When using a Hashtable, you specify an object that is used as a key, and the value that you want linked to that key. The key is then hashed, and the resulting hash code is used as the index at which the value is stored within the table.
the difference between Hashable and TreeSet is that treeset don't need hashCode, it just need to know if you need the take the item left or right in the tree. for that you can use Compare and nothing more.
in hashTable a compare will suffice, because it's build differently, each object get to his cell by hashing it, not by comparing it to the items already in the collection.
so the answer is no, you can' use Person in hashtable just with compareTo. u must override hashCode() and equals() for that
i also suggest you read this article on hashtables
HashTable does use equals and hashCode. Every class has those methods. If you don't implement them, you inherit them.
Whether you need to implement them depends on whether the inherited version is suitable for your purposes. In particular, since Person has no specified superclass, it inherits the Object methods. That means a Person object is equal only to itself.
Do you need two distinct Person objects to be treated as being equal as HashTable keys?
if my class implements comparable, then does it mean I dont have to override equals and hashcode method for using my objects as keys in Hash collections. eg
No, you still need to implement equals() and hashCode(). The methods perform very different functions and cannot be replaced by compareTo().
equals() returns a boolean based on equality of the object. This is usually identity equality and not field equality. This can be very different from the fields used to compare an object in compareTo(...) although if it makes sense for the entity, the equals() method can be:
#Overrides
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
} else {
return compareTo((Person)obj) == 0;
}
}
hashCode() returns an integer value for the instance which is used in hash tables to calculate the bucket it should be placed in. There is no equivalent way to get this value out of compareTo(...).
TreeSet needs Comparable, to add values to right or left of tree. HashMap needs equals() and Hashcode() methods that are available from Object Class but you have to override them for your purpose.
If a class implements Comparable, that would suggest that instances of the class represent values of some sort; generally, when classes encapsulate values it will be possible for there to exist two distinct instances which hold the same value and should consequently be considered equivalent. Since the only way for distinct object instances to be considered equivalent is for them to override equals and hashCode, that would imply that things which implement Comparable should override equals and hashCode unless the encapsulated values upon which compare operates will be globally unique (implying that distinct instances should never be considered equivalent).
As a simple example, suppose a class includes a CreationRank field of type long; every time an instances is created, that member is set to a value fetched from a singleton AtomicLong, and Comparable uses that field to rank objects in the order of creation. No two distinct instances of the class will ever report the same CreationRank; consequently, the only way x.equals(y) should ever be true is if x and y refer to the same object instance--exactly the way the default equals and hashCode work.
BTW, having x.compare(y) return zero should generally imply that x.equals(y) will return true, and vice versa, but there are some cases where x.equals(y) may be false but x.compare(y) should nonetheless return zero. This may be the case when an object encapsulates some properties that can be ranked and others that cannot. Consider, for example, a hypohetical FutureAction type which encapsulates a DateTime and an implementation of a DoSomething interface. Such things could be ranked based upon the encapsulated date and time, but there may be no sensible way to rank two items which have the same date and time but different actions. Having equals report false while compare reports zero would make more sense than pretending that the clearly-non-equivalent items should be called "equal".

Equals() method is called on existing object or incoming object in collections

Can anyone please clarify when we check equality on collections, equals() method is called on incoming object or on those objects which are there in collection. for ex.
If a Set or a Hashmap has objects object1, object2 and object3 and a fourth object called object4 tries to get into the Set or it is compared with the already existing three objects in case of hashmap then equals() method is called on this fourth object and the already existing three objects are passed one by one or reverse is true.?
The answer doesn't matter much (and might vary betwen implementations), because by contract, A.equals(B) if and only if B.equals(A). Not respecting this contract is a recipe for strange and incoherent behavior from the collections.
There is no way to know, unless you are considering a very specific collection implementation. You are not supposed to rely on it. The equals method should be reflexive, i.e., x.equals(y) should give the same result as y.equals(x), unless one of them is null.
There's should be no diference between a.equals(b) and b.equals(a) (if a and b not null )The equals should be symmetric. There's no guarantee that what form(a.equals(b) or b.equals(a)) being used.
Well...As I just checked in eclipse, the equals() method of incoming objects are called. Eclipse passes ref. of pre-existing objects in equals() method of incoming object one by one.
I know as you all are saying, It is written in Sun's equals() method contract that equals method should be reflexive, symetric and transitive.
This question came in mind when I was thinking that collections could have been more optimized if it is somehow checked pro-actively that the two references (that are being checked for equality) point to the same object or not. If they are, then it does make sense to by-pass equals() and hashcode() method.

equals and hashCode

I am running into a question about equals and hashCode contracts:
here it is
Given:
class SortOf {
String name;
int bal;
String code;
short rate;
public int hashCode() {
return (code.length() * bal);
}
public boolean equals(Object o) {
// insert code here
}
}
Which of the following will fulfill the equals() and hashCode() contracts for this
class? (Choose all that apply.)
Correct Answer
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;
I have a question about the last choice D, say if the two objects
A: code.length=10, bal=10, rate = 100
B: code.length=10, bal=100, rate = 10
Then using the equals() method in D, we get A.equals(B) evaluating to true right? But then they get a different hashCode because they have different balances? Is it that I misunderstood the concept somewhere? Can someone clarify this for me?
You're right - D would be inappropriate because of this.
More generally, hashCode and equals should basically take the same fields into account, in the same way. This is a very strange equals implementation to start with, of course - you should normally be checking for equality between each of the fields involved. In a few cases fields may be inter-related in a way which would allow for multiplication etc, but I wouldn't expect that to involve a string length...
One important point which often confuses people is that it is valid for unequal objects to have the same hash code; it's the case you highlighted (equal objects having different hash codes) which is unacceptable.
You have to check at least all the fields used by .hashCode() so objects which are equal do have the same hash. But you can check more fields in equals, its totally fine to have different objects with the same hash. It seems your doing SCJP 1.6? This topic is well covered in the SCJP 1.6 book from Katherine Sierra and Bert Bates.
Note: thats why its legit to implement a useful .equals() while returning a constant value from .hashCode()
It's all about fulfilling the contract (as far as this question is concerned). Different implementation (of hasCode and equal) has different limitations and its own advantages - so its for developer to check that.
but then they get different hashCode because they have a different balance?
Exactly! But that's why you should choose option C. The question wants to test your grasp on fulfilling the contract concept and not which hascode will be better for the scenario.
More clarification:
The thing you need to check always is :
Your hashCode() implementation should use the same instance variables as used in equals() method.
Here these instance variables are : code.length() and bal used in hashCode() and hence you are limited to use these same variables in equals() as well. (Unless you can edit the hashCode() implementation and add rate to it)
hashCode() method is used to get a unique integer for given object. This integer is used to determined the bucket location, when this object need to be stored in some HashTable like HashMap data structure. But default, Object's hashCode() method returns an integer to represent memory address where object is stored.
equals() method, as name suggest, is used to simply verify the equality of two objects. Default implementation just simply check the object references of two object to verify their equality.
equal objects must have equal hash codes.
equals() must define an equality relation. if the objects are not modified, then it must keep returning the same value. o.equals(null) must always return false.
hashCode() must also be consistent, if the object is not modified in terms of equals(), it must keep returning the same value.
The relation between the two method is:
whenever a.equals(b) then a.hashCode() must be same as b.hashCode().
refer to: https://howtodoinjava.com/interview-questions/core-java-interview-questions-series-part-1/
In general, you should always override one if you override the other in a class. If you don't, you might find yourself getting into trouble when that class is used in hashmaps/hashtables, etc.

Categories