How does equals() method work in Java [duplicate] - java

This question already has answers here:
What is the difference between == and equals() in Java?
(26 answers)
Closed 9 years ago.
The equals method compares whether two object values are equal or not. My question is how it compares the two objects? How can it tell the two objects are equal or not? I want to know based on what it compares the two objects. I am not including the hashCode method.

The default implementation, the one of the class java.lang.Object, simply tests the references are to the same object :
150 public boolean equals(Object obj) {
151 return (this == obj);
152 }
The reference equality operator is described like this in the Java Specification :
At run time, the result of == is true if the operand values are both
null or both refer to the same object or array; otherwise, the result
is false.
This default behavior isn't usually semantically satisfying. For example you can't test equality of big Integer instances using == :
Integer a = new Integer(1000);
Integer b = new Integer(1000);
System.out.println(a==b); // prints false
That's why the method is overridden :
722 public boolean equals(Object obj) {
723 if (obj instanceof Integer) {
724 return value == ((Integer)obj).intValue();
725 }
726 return false;
727 }
which enables this :
System.out.println(a.equals(b)); // prints true
Classes overriding the default behavior should test for semantic equality, based on the equality of identifying fields (usually all of them).
As you seem to know, you should override the hashCode method accordingly.

Consider following example,
public class Employee {
String name;
String passportNumber;
String socialSecurityNumber;
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee();
boolean isEqual = e1.equals(e2); // 1
System.out.println(isEqual);
}
}
In the code at comment //1 it calls inherited equals method from Object class which is simply comparing references of e1 and e2. So it will always give false for each object created by using new keyword.
Following is the method excerpt from Object
public boolean equals(Object obj) {
return (this == obj);
}
For comparing equality check JLS has given equals method to override in our class. It is not final method. JLS doesn't know on what basis programmar wants to make two objects equal. So they gave non-final method to override.
hashcode does not play role to check object's equality. hashcode checks/finds the Bucket where object is available. we use hashcode in hashing technique which is used by some classes like HashMap..
If two object's hashcode are equals that doesn't means two objects are equal.
For two objects, if equals method returns true then hashcode must be same.
You will have to override equals method to decide on which basis you want object e1 and e2 in above code is equal. Is it on the basis of passportNumber or socialSecurityNumber or the combination of passportNumber+socialSecurityNumber?
I want to know based on what it compares the two objects.
Answer is, by default with the help of inherited Object class's equals method it compares two object's reference equality by using == symbol. Code is given above.

logically, equals does not compare objects (however you can do anything with it), it compares values. for object comparison there is '==' operator

Related

How == and equal works in java in Case of Integer Object? [duplicate]

This question already has answers here:
Java: Integer equals vs. ==
(7 answers)
Closed 4 years ago.
I have found many possible duplicates question on this but none clarifies my doubt on how it works?
Integer a =25654; // a.hashCode()=>25654
Integer b =25654; // b.hashCode()=>25654
System.out.println(a.equals(b)); => true
System.out.println(a == b); => false
I have read this answer somewhere..
If no parent classes have provided an override, then it defaults to the method from the ultimate parent class, Object, and so you're left with the Object#equals(Object o) method. Per the Object API this is the same as ==; that is, it returns true if and only if both variables refer to the same object, if their references are one and the same. Thus you will be testing for object equality and not functional equality.
in this case both object have same memory address(as per hashcode) still why does it returns false when we compare using == ? or the actual memory address is different? please correct me if i am wrong. Thanks
Object.hashCode:
The hashCode method defined by class Object does return distinct
integers for distinct objects.
But Integer.hashCode overrides Object.hashCode:
returns a hash code value for this object, equal to the primitive int
value represented by this Integer object.
which means Integers with same hashCode does not have to share the same object.
The source code of Integer.hashCode
#Override
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
If you let:
Integer a = 127;
Integer b = 127;
System.out.println(a.equals(b)); // true
System.out.println(a == b); // true
this is because Integers between [-128, 127] could be cached.
in this case both object have same memory address(as per hashcode)
still why does it returns false when we compare using == ? or the
actual memory address is different? please correct me if i am wrong.
Thanks
The hashcode has not to be considered as the memory address because the internal address of an object may change through the time.
The specification of hashCode() never state that two objects with the same hashcode value refer necessarily the same object.
Even two objects with the same hashcode may not be equals in terms of Object.equals().
But the specification states :
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.
And this is verifiable in your example :
Integer a =25654; // a.hashCode()=>25654
Integer b =25654; // a.hashCode()=>25654
System.out.println(a.equals(b)); => true
a and b refer to objects that are equals(), and yes their hash code is indeed the same.
Your quotation doesn't refer to hashCode() but to the default Object.equals() method that will be used if no overriding was done for equals().
For example if I don't override equals() and hashCode() for a Foo class :
Foo fooOne = new Foo(1);
Foo fooOneBis = new Foo(1);
fooOne.equals(fooOneBis); // return false
The two objects have the same state but they are not equals as under the hood is used Object.equals() that compares the object itself and not their state.
And indeed equal() will return true only if the variables refer the same object :
Foo foo = new Foo(1);
foo.equals(foo); // return true

Is it recommended to use hashcode to determine equality in Java? [duplicate]

This question already has answers here:
Java: Use hashCode() inside of equals() for convenience?
(7 answers)
Closed 7 years ago.
Let's say we have a hashcode() function, which will then be used inside our equals() method to determine the equality of two objects. Is this an allowed/accepted approach?
Assume that we use a simple implementation of a hash code. (For example a few instance variables multiplied by prime numbers.)
This is a terrible way to check for equality, mostly since Objects don't have to be equal to return the same hashcode.
You should always use the equals method for this.
The general rule is:
If the equals method returns true for Objects a and b, the hashCode
method must return the same value for a and b.
This does not mean, that if the hashCode method for a and b returns
the same value, the equals method has to return true for these two
instances.
for instance:
public int hashCode(){
return 5;
}
is a valid, though be it inefficiënt, hashcode implementation.
EDIT:
to use it within an equals method would be something like this:
public class Person{
private String name;
public Person(String name){ this.name = name;}
public String getName(){ return this.name;}
#Override
public boolean equals(Object o){
if ( !(o instanceof Person)){ return false;}
Person p = (Person)o;
boolean nameE = this.name == null ? p.getName() == null : this.name.equals(p.getName());
boolean hashE = nameE ? true : randomTrueOrFalse();
// the only moment you're sure hashE is true, is if the previous check returns true.
// in any other case, it doesn't matter whether they are equal or not, since the nameCheck returns false, so in best case, it's redundant
return nameE && hashE;
}
#Override
public int hashCode(){
int hash = generateValidHashCode();
return hash;
}
}
It is a very bad practice. Hashes are supposed to have a minimal amount of collisions, but usually you have more possibilities for objects than the amount of possible hashes and because of the pigeonhole principle a few distinct objects must have the same hash.
When comparing hashes, you have a certain chance of getting "false positives".
Actually, it is not a bad idea!
But make sure you use this method to determine inequality, not equality. Hashing code may be faster than checking equality, especially when hashcode is stored (for example in java.lang.String).
If two object have different hashcodes they must be different, else they may be the same. For example you may use this method as the following
Object a, b;
if(a.hashCode() == b.hashCode()){
if(a.equals(b)) return true;
}
return false;
Be aware that in some cases code above may be slower than using only equals(), especially when in most cases a does equal b.
From documentation of Object.java:
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.
Don't do this
While it is correct that you need to override equals() and hashCode() in pairs, having the same hash is not the same as having the same values.
Put some effort into really thinking the equality thing through. Don't shortcut here it will bite you later.

Java equal method explanation on the following code

I have been reading a book called Thinking in Java on Java(I come from C background). I came across the following two set of codes
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
}
//Output: true
I understand that this equal method is comparing the reference. But n1 and n2 are two object residing in ´two different "bubble" in the heap. So how come they are equal?
Another example code is
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} /* Output:false
}
Why does this give false? Your in depth answer would be much anticipated. Thank you.
The behavior of equals in your custom classes is entirely up to you. If you override it, you decide when two objects of your class are considered equal to each other. If you don't override it, you get the default implementation of Object class, which checks if both references refer to the same object (i.e. checks if v1==v2 in your example, which is false).
Root of the issue :
You have not overrriden eqauals and hashCode and then JVM assigns a new hashCode to any object you create in the case of Value class
=================
Solution :
You will need to define the criteria on which the identities of the value object is measured i.e do the following
1) Override the equals method and specify that the equality is checked over the value of the instance variable i
2) Override Hashcode and use instance variable i for the hashCode comparison
== is used in the equals method in the object class to avoid unnecessary calculation if the two refrences point to the same object and if not go ahead with the calculation and comparisons
public boolean equals(Object anObject)
{
if (this == anObject) {
return true;
}
else{
// Do the calculation here to check the identity check
}
I understand that this equal method is comparing the reference.
Wrong. In the Object class, this method contains a referential comparison, but Integer has it's own implementation, which overrides the one provided by Object.
It compares the values of the two Integers, not their references.
Integer is valuable type. So comparing to Integer variables performing by comparing their values. Which are equal in your particular case.
Comparing two objects (reference type) performing by comparing the references, which are not equal.
You could write your own comparison logic by overloading the equals() method in your class.
Integer has the method equals() that compare the value, and your Value class doesn't. It makes the Value class with equals compare the "pointer", and they're different.
If you override the method equals in your class Value comparing the attribute i from the class, it would return true.
For example
public boolean equals(Object o){
return (this.i == ((Value) o).i) ? true : false;
}
Equals method in all Wrapper classes is overridden by default in java. That's is why first snippet works.
For your own classes, you have to provide an implementation of equals method.
By default the equal method in Java check if the two Object references are the same. You can #Override the method, and do what you want. So it is normal that you get False, because the two Object are different.
So how come they are equal?
Integer is an Object. On the other side int is a simple type.
Integer's equals() method compare int inside, because it's overriding Object equals() method. int's there has the same value.
Why does this give false?
Your Value class doesn't override equal's method, so then refferences are compared, exactly like when you write v1 == v2. In this case they are different Objects so it's false.
Because you have not override equals method. If you do not override it then it will check if the reference are equal or not and return accordingly.
You can refer equals() method defined in Integer class.
System.out.println(n1.equals(n2)) // this prints true because it refers to Integer equals method.
Similarly you will have to override it for your Value class like.
class Value {
int i;
#Override
public boolean equals(Object obj) {
boolean returnValue = false;
if (obj != null && obj instanceof Value) {
Value valObj = (Value) obj;
if (this.i == valObj.i) {
returnValue = true;
}
}
return returnValue;
}
}
Now System.out.println(v1.equals(v2)); prints true.
Hi your understanding of equals and == is completely wrong or opposite to what it actually is.
equals() method also checks for reference as == does, there is no difference between both of them unless you override the equals method.
== check for reference equality. For better understanding see Object class source code.
public boolean equals(Object obj) {
return (this == obj);
}
Why is it working in your case? is because Integer class overrides the equals method in it.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
n
}
Now when you use your custom class to check equality what it is doing is basically calling.
v1==v2
How it can give you true? They both have different memory locations in heap.
If still things are not clear put break points in your code and run it in debug mode.

functioning of (== ) in terms of hashCode

String s1="abc";
String s2=new String("abc");
when we compare the both
s1==s2; it return false
and when we compare it
with s1.hashCode()==s2.hashCode it return true
i know (==) checks reference id's .Does it returning true in above comparison because above hashCode are saved to same bucket??Please give me explanation
Don't forget that your hash codes are primitive integers, and comparing primitives using == will compare their values, not their references (since primitives don't have references)
Hence two strings having the same contents will yield the same hash code, and a comparison via == is perfectly valid.
The concept of a bucket is only valid when you put an object into a hashed collection (e.g. a HashSet). The value of the hash code dictates which bucket the object goes into. The hash codes themselves aren't stored.
First comparison fails because they are two different objects. Second comparison works because they are comparing the output of the hashCode() function, which produces the same value for both.
When comparing objects using the equality operator (==) you are testing the equality of the Object Reference. Object References are only equal if they are the same object.
What is usually meant is the equality of the concept/information the object encapsulates. And this is best determined by the equal(Object obj) method.
For String this would be:
s1.equals(s2);
When you compare the two Strings using s1==s2, you are comparing references. Since just before that line you created a new String object by copying the old one, both references refer to different objects, even though they contain the same value.
On the other hand, what the hashCode method does, depends on how it is implemented. The specification says that it has to comply with the equals function (whose behavior also depends on how it is implemented in the concrete type): If two objects are equal according to the equals method, they must return the same hash code. Since equals for String compares the values (not the references), both hashCode calls have to return the same value. And since hashCode returns an int, which is a primitive data type, your == comparison actually compares values and therefore works as expected.
Note: If you had done the same experiment for a class different from String that doesn't override the equals and hashCode methods (which is perfectly valid; it's just another way of defining equality on your type of object), it would have returned false for the hashCode comparison, too:
public class MyObject {
private int value;
public MyObject(MyObject toCopy) {
this.value = toCopy.value;
}
public MyObject(int value) {
this.value = value;
}
public static void main(String[] args) {
MyObject s1 = new MyObject(0);
MyObject s2 = new MyObject(s1);
System.out.println(s1 == s2); // false
System.out.println(s1.hashCode() == s2.hashCode()); // false
}
}
It all depends on how the programmer of the class defines which objects to consider equal.

What does equals(Object obj) do?

I´ve often found an equals method in different places. What does it actually do? Is it important that we have to have this in every class?
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (obj == null)
{
return false;
}
if (obj instanceof Contact)
{
Contact other = (Contact)obj;
return other.getFirstName().equals(getFirstName()) &&
other.getLastName().equals(getLastName()) &&
other.getHomePhone().equals(getHomePhone()) &&
other.getCellPhone().equals(getCellPhone());
}
else
{
return false;
}
}
It redefines "equality" of objects.
By default (defined in java.lang.Object), an object is equal to another object only if it is the same instance. But you can provide custom equality logic when you override it.
For example, java.lang.String defines equality by comparing the internal character array. That's why:
String a = new String("a"); //but don't use that in programs, use simply: = "a"
String b = new String("a");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
Even though you may not need to test for equality like that, classes that you use do. For example implementations of List.contains(..) and List.indexOf(..) use .equals(..).
Check the javadoc for the exact contract required by the equals(..) method.
In many cases when overriding equals(..) you also have to override hashCode() (using the same fields). That's also specified in the javadoc.
Different classes have different criteria for what makes 2 objects "equal". Normally, equals() returns true if it is the same Object:
Object a = new Object();
Object b = new Object();
return(a.equals(b));
This will return false, eventhough they are both "Object" classes, they are not the same instance. a.equals(a) will return true.
However, in cases like a String, you can have 2 different instances but String equality is based on the literal characters that make up those Strings:
String a = new String("example");
String b = new String("example");
String c = new String("another");
a.equals(b);
a.equals(c);
These are all different instances of String, but the first equals will return true because they are both "example", but the 2nd will not because "example" isn't "another".
You won't need to override equals() for every class, only when there is a special case for equality, like a class that contains 3 Strings, but only the first String is used for determining equality. In the example you posted, there could have been another field, description which could be different for 2 different "Contacts", but 2 "Contacts" will be considered equal if those 4 criteria match (first/last name, and home/cell phone numbers), while the description matching or not matching doesn't play into whether 2 Contacts are equal.
Aside from everything given by Bozho, there are some additional things to be aware of if overriding equals:
something.equals(null) must always return false - i.e. null is not equal to anything else. This requirement is taken care of in the second if of your code.
if it is true that something == something else, then also something.equals(something else) must also be true. (i.e. identical objects must be equal) The first if of your code takes care of this.
.equals SHOULD be symetric for non-null objects, i.e. a.equals(b) should be the same as b.equals(a). Sometimes, this requirement breaks if you are subclassing and overriding equals in the parent-class and in the subclass. Often equals contains code like if (!getClass().equals(other.getClass())) return false; that at least makes sure that a diffrent object type are not equal with each other.
If you override equals you also MUST override hashCode such that the following expression holds true: if (a.equals(b)) assert a.hashCode() == b.hashCode(). I.e. the hash code of two objects that are equal to each other must be the same. Note that the reverse is not true: two objects that have the same hash code may or may not be equal to each other. Ususally, this requirement is taken care of by deriving the hashCode from the same properties that are used to determine equality of an object.
In your case, the hashCode method could be:
public int hashCode() {
return getFirstName().hashCode() +
getLastName().hashCode() +
getPhoneHome().hashCode() +
getCellPhone().hashCode();
}
If you implement Comparable that compares two objects if they are smaller, larger, or equal to each other, a.compareTo(b) == 0 should be true if and only if a.equalTo(b) == true
In many IDEs (e.g. Eclipse, IntelliJ IDEA, NetBeans) there are features that generate both equals and hashCode for you, thereby sparing you of tedious and possibly error-prone work.
The equals method is used when one wants to know if two objects are equivalent by whatever definition the objects find suitable. For example, for String objects, the equivalence is about whether the two objects represent the same character string. Thus, classes often provide their own implementation of equals that works the way that is natural for that class.
The equals method is different from == in that the latter tests for object identity, that is, whether the objects are the same (which is not necessarily the same as equivalent).
It enables you to re-define which Objects are equal and which not, for example you may define that two Person objects as equal if the Person.ID is the same or if the Weight is equal depending on the logic in your application.
See this: Overriding the java equals() method quirk
By default, the Object class equals method invokes when we do not provide the implementation for our custom class. The Object class equals method compares the object using reference.
i.e. a.equals(a); always returns true.
If we are going to provide our own implementation then we will use certain steps for object equality.
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return
false.
public class ObjectEqualExample{
public static void main(String []args){
Employee e1 = new Employee(1, "A");
Employee e2 = new Employee(1, "A");
// if we are using equals method then It should follow the some properties such as Reflexive, Symmetric, Transitive, and constistent
/*
Reflexive: a.equals(a) always returns true;
Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.
Consistent: a.equals(b) should be the same result without modifying the values of a and b.
Note: default equals method check the reference i.e. == operator.
Note: For any non-null reference value a, a.equals(null) should return false
*/
System.out.println(e1.equals(e1));
System.out.println(e1.equals(e2));
}
}
class Employee {
private int id;
private String name;
#Override
public String toString() {
return "{id ="+id+", name = "+name+"} ";
}
#Override
public boolean equals(Object o) {
// now check the referenc of both object
if(this == o) return true;
// check the type of class
if(o == null || o.getClass() != this.getClass()) return false;
// now compare the value
Employee employee = (Employee)o;
if(employee.id == this.id && employee.name.equals(this.name)) {
return true;
} else return false;
}
public int hashCode() {
// here we are using id. We can also use other logic such as prime number addition or memory address.
return id;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
One more thing, maps use the equals method to decide if an Object is present as a key. https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

Categories

Resources