What am I getting wrong about Java's '==' and '.equals'? - java

EDIT: I'm new to java and am going through the official documentation in preparation for an upcoming subject in my Computer Science studies.
Original question:
So I checked this thread re: java == and .equals and am getting some unexpected results in dummy code that I'm writing.
I have this:
public class HelloWorld {
public static void main(String[] args){
Double double1 = 1.0; //object 1
Double double2 = 1.0; //object 2, which should be a different memory address?
System.out.println(double1.equals(double2)); //compare using the Object.equals() method
System.out.println(double1 == double2); //compare with ==
}
}
//Results are:
//true
//false
As expected, == produces a false because the two objects refer to different memory addresses.
However the double.equals(double2) is producing a true, which is not what I expected. In this example, I'm not overriding the default .equals() inherited from Object. My understanding is that equals checks for reference equality as well as values.
So why does double1.equals(double2) return true instead of false in this example? Are't double1 and double2 referring to two difference objects and therefore equals() should return false?

You didn't override equals, but the implementation of java.lang.Double does override it, to return true if the underlying values compare equal (plus a couple of edge cases).
https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#equals-java.lang.Object-

My understanding is that equals checks for reference equality as well as values.
That is incorrect.
The version of equals(Object) defined by java.lang.Object does that. But many classes override equals(Object) to have different semantics.
Double overrides it, and so do all of the other "primitive wrapper" classes, and String ... and many, many more.
The semantics of the override are typically equal-by-value, but not always. And some classes don't override equals. Examples where equals is not overridden that trip people up are StringBuilder and array types!
To find out the semantics for SomeType.equals(Object) you need to start with the javadocs for SomeType ... not Object.

Related

The equals implementation in Object

I was reading about the equals method in Java, and I heard people say that == tests for reference equality (whether they are the same object). .equals() tests for value equality (whether they are logically "equal").
I believe it is true but, If you look at the source code for .equals(), it simply defers to ==
From the Object class:
public boolean equals(Object obj) {
return (this == obj);
}
Now I am confused. What I see is we are testing if the current object have the same reference to the explicit parameter. Does it test for reference equality or for value equality?
From the Javadoc:
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).
Object being the ultimate base class, this is the only definition of equals it can provide. There are no fields to compare across instances, so an instance can only be equal to itself.
In a comment you've said:
I would like to know about String comparison I see people use it all the time
Your question asks about Object, not String. String overrides equals, because Object's definition of equals isn't appropriate for String. Consequently, String defines its own (in keeping with the semantics required for equals implementations).
Object doesn't have a value to compare anything with.
But in order to make sense, it has to provide an implementation for methods such as equals() or hashCode().
So, to be precise: classes deriving from Object should override equals() in case they to replace reference equality with "value semantics".

Why does the equals() method return false when the two objects are identical?

public class Test {
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
System.out.print((o1 == o2) + " " + (o1.equals(o2)));
}
}
I read this in a different answer:
The == operator tests whether two variables have the same references (aka pointer to a memory address).
Whereas the equals() method tests whether two variables refer to objects that have the same state (values).
Here, since o1 and o2 reference two different objects, I get why == returns false.
But both the objects are created using the default constructor of the Object class, and therefore have same values. Why does the equals() method return false?
The implementation of equals() supplied by java.lang.Object is defined to return false, unless the references refer to the same object, in which case it returns true.
This is by design (the method mimics the behaviour of ==) and encourages programmers to implement their own version of equals(), if appropriate, for their class. For example, see java.lang.String#equals which compares the contents if another String is passed as an argument.
You have to write your own equals method that overrides the equals method of class Object because that method returns true if this object is the same as the object in the argument and false otherwise.
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). (for more information, read Javadoc)
All Java objects inherit from the Object class. The methods of Object, therefore, are available to all Java objects. One of these methods is equals().
The implementation for equals() in class Object, by default, is identical to the == operator.
If a programmer wishes to use equals() to test objects for value equality, he must override equals() and provide his own implementation (that should comply with the general contract for equals(); refer to the Javadoc).

Why in the first print it says different while a and b are indentical?

public class SomeClass {
public static void main(String[] args){
int[] a={1,2,3};
int[] b={1,2,3};
int[] c=a;
String s="Neanderthal";
String s2="Neanderthal";
String s3=s;
System.out.println((a.equals(b))?"Same":"Different");
System.out.println((a.equals(c))?"Same":"Different");
System.out.println((s.equals(s2))?"Same":"Different");
System.out.println((s.equals(s3))?"Same":"Different");
}
}
The 1st system.out.print returns the value different and i cannot see a reason for this, and all the others are the same. Please help me understand this
Unlike Strings which are compared for equality character-by-character *, Java arrays are compared only for reference equality. You need to use Array.equals or Array.deepEquals to do the comparison:
System.out.println(Arrays.equals(a, b) ? "Same" : "Different");
* Since your code uses string literals, s and s2 would refer to the same object instance. However, this is not critical to understanding the issue at hand, because interning is not applicable to arrays.
When you say
int[] a={1,2,3};
int[] b={1,2,3};
a is pointing to an array, b is pointing to another array. Both the arrays are not same in the memory. That is, they both are pointing to different memory locations.Like :
a------------->|mem_loc_1|
b------------->|mem_loc_2|
Hence, equals() method tells you that both references are NOT pointing to same object.
Whereas when you say c= a;, the situation is :
a -------------> |mem_loc_1| <---------------- c
Hence equals() tells you that YES, a and c references reference to same objects.
Conclusion, when you say c = a; there are TWO references, but a single object in the memory.
P.S. Sorry for the bad graphical representation,just wanted to simplify things.
because it doesn't do deep equals and does just shallow equals, Use Arrays.deepEquals(); to get expected output
Before understanding above concept you need to note few things :
equals() method is defined in Object class, and any class can
override it.
By default equals() method use memory address of objects to compare them.
So, if you do not overriding it then it will call Object's method.
String class has overridden version of equals() method.
Now come on your program :
In first print statement you are comparing two different object which has not overridden equals() method, so it use Object's method and obviously it check memory address which is different.
In second print statement two reference variable refer same object so its address are same and equals() method return true.
In other print statements for string, which has overridden equals() method, so it will check only actual (here string value) content of object it doesn't matter two String reference variable referring same object or different.

Same object different hash code?

class Rational {
int num = 0;
int denom = 0;
public Rational(int num, int denom) {
this.num = num;
this.denom = denom;
}
public static void main(String[] args) {
Rational r1 = s.new Rational(1, 1);
Rational r2 = s.new Rational(1, 1);
System.out.println(r1.hashCode());
System.out.println(r2.hashCode());
}
I have two of the same objects, but they have different hashCode. Why is that?
I tried overriding the .equal method in Rational so r1.equals(r2) == true. But they still produce different Java hashCode.
They are not the same object; they are two different objects with the same value. Just because there's another Jeroen Vannevel in the world doesn't mean it's me.
hashCode() is not linked to equals(): they both have a contract they have to adhere to and they are related but they do not directly influence eachother. That's why you should always override both of these methods and not just one.
I have two of the same objects
"Same" usually means, literally, one object. Here what you have are equivalent objects.
...but they have different hashCode. Why is that?
Because you haven't overridden hashCode to replace the default implementation. Overriding equals doesn't change hashCode (you almost always have to override both if you override equals).
The hashCode documentation says this about the default implementation in Object:
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.)
So you'll get distinct integers (usually) for different instances, even if they're equivalent, unless you replace hashCode.
In your case, you could do this:
#override
public int hashCode() {
return this.num ^ this.denom;
}
...and have a reasonable hashCode for Rational (be sure to override equals as well), but there are lots of other ways. Just stick to the contract:
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 hash tables.

difference between equals() and hashCode()

I want a brief definition about the equals() , "==" and hashCode(). If i run following code means the output will be "true false 2420395 2420395". But i had understand that equals() method compares the string and "==" compares the reference. But in output the hashCcode() method prints the reference number for both strings as same then why the "==" returns "false".
String str = "Name";
String str1 = new String("Name");
if (str.equals(str1))
System.out.println("true");
else
System.out.println("false");
if (str == str1)
System.out.println("true");
else
System.out.println("false");
System.out.println(str.hashCode());
System.out.println(str1.hashCode());
The equals() and hashCode() methods prove to be very important, when objects implementing these two methods are added to collections. If implemented incorrectly it might screwed up your life.
equals() : This method checks if some other object passed to it as an argument is equal the object in which this method is invoked. It is easy to implement the equals() method incorrectly, if you do not understand the contract. Before overriding this method, following “properties” need to keep in mind -
Reflexive: o1.equals(o1) - which means an Object (e.g. o1) should be equal to itself
Symmetric: o1.equals(o2) if and only o2.equals(o1)
Transitive: o1.equals(o2) && o2.equals(o3) implies that o1.equals(o3) as well
Consistent: o1.equals(o2) returns the same as long as o1 and o2 are unmodified
null comparison : !o1.equals(null) - which means that any instantiable object is not equal to null. So if you pass a null as an argument to your object o1, then it should return false.
Hash code value: o1.equals(o2) implies o1.hashCode() == o2.hashCode() . This is very important. If you define a equals() method then you must define a hashCode() method as well. Also it means that if you have two objects that are equal then they must have the same hashCode, however the reverse is not true
From java source code
*
* #param obj the reference object with which to compare.
* #return {#code true} if this object is the same as the obj
* argument; {#code false} otherwise.
* #see #hashCode()
* #see java.util.HashMap
*/
public boolean equals(Object obj) {
return (this == obj);
}
hashCode(): This method returns a hashCode() value as an Integer and is supported for the benefit of hashing based java.util.Collection classes like Hashtable, HashMap, HashSet etc. If a class overrides the equals() method, it must implement the hashCode() method as well.Before overriding this method, you need to keep in mind
Whenever hashCode() method is invoked on the same object more than once during an execution of a Java program, this method must consistently return the same result. The integer result need not remain consistent from one execution of the program to the next execution of the same program.
If two objects are equal as per the equals() method, then calling the hashCode() method in each of the two objects must return the same integer result. So, If a field is not used in equals(), then it must not be used in hashCode() method.
If two objects are unequal as per the equals() method, each of the two objects can return either two different integer results or same integer results (i.e. if 2 objects have the same hashCode() result does not mean that they are equal, but if two objects are equal then they must return the same hashCode() result).
As per java source code
As much as is reasonably practical, the hashCode method defined by java.lang.Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer)
hashCode() does not return the object's reference, but a hash of the object, computed in some way. == does not compare objects using the value of hashCode() but, as you correctly say, by the value of the objects' references.
.equals() compares the actual content of the string.
The "==" operator compares if the two objects are the same reference in memory. If you were to do str = str1;, then the double-equals operator would return true because they point to the same reference in memory.
hashCode() returns a hash of the object in an arbitrary manner. The value returned will always be unique as long as the method is not overridden in some way. If .equals() returns true, the hash code should be the same.
You can read the hashCode documentation. In a few words it says that if (obj1.equals(obj2) is true then obj1.hashCode()==obj2.hasCode() must be true to be a valid implementation.
Note that it does not mean that two different objects cannot share the same hash code. Actually, this example is a valid (but awful) implementation of the method:
class MyClass {
public int hashCode() {return 0;}
}
equals() and hashCode() are different methods and hashCode method should not be used to check if two object references are same.
Reason: hashCode just returns int value for an Object, even two different objects can have same hashCode integer. The value returned by hashCode() is the object's hash code, which is the object's memory address in hexadecimal.
equals() checks if the two object references are same. If two objects are equal then their hashCode must be the same, but the reverse is not true.
As other said '==' compares references. But the two methods are just methods doing something which can be overridden.
Every method does something. If you want to know what it exactly does and what is its meaning you need to read the documentation.
You may override those methods in anyway you want. But please note that you must follow JAVA documentation for these two methods. Because they are used by other classes. For example equals() is used while you try find an object in a list and .hashCode() is used in some hashtable classes provided by JAVA class library.
equals() only compare string it's does not check reference of string
but '==' check reference and data both
in 1st case String str = "Name"; only one object is created but in
2nd case Two object is created
String str1 = new String("Name");
then reference are not same of both string that means it returns false

Categories