Reference Comparison and Content Comparison in Java - java

I was learning about Reference (or Address) comparison and Content comparison. The below statement makes me confused:
If a class does not override the equals method, then by default, it uses the equals(Object o) method of the closest parent class that has overridden this method.
Point to note: I haven't overridden the .equals() method and I'm only practicing it in my main class.
Below is my code:
package com.reference.content.comparison;
public class ReferenceAndContentComparison {
public static void main(String[] args) {
/* "==" operator is used for REFERENCE (or address) comparison. It means, it check if both objects point to same memory location or not.
* ".equals()" method is used for CONTENT comparison (in String class). It means, it check if both objects have same value or not.
*
* MAIN DIFFERENCES ARE:
* 1. "==" is an operator while ".equals()" is a method (of Object class).
* 2. Line 7 to 8.
* 3. ".equals()" method of Object class is used for REFERENCE comparison but in String class, it is used for CONTENT reference (by overriding .equals()).
* 4. If a class does not override the equals method, then by default, it uses the equals(Object o) method of the closest parent class that has overridden this method.
* 5. When comparing two Strings using .equals() method, their content is compared, and not their references.
* Link for point 5: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equals-java.lang.Object-
*/
String s1 = "HELLO";
String s2 = "HELLO"; // references s1
String s3 = new String("HELLO"); // new instance but same content
System.out.println(s1 == s2); // true; Both s1 and s2 refer to same objects. Their addresses are same.
System.out.println(s1 == s3); // false; Addresses of s1 and s3 are different.
System.out.println(s1.equals(s2)); // true; Content of both s1 and s2 are same. Content Reference, because s1 and s2 are string class objects.
System.out.println(s1.equals(s3)); // true; Content of both s1 and s3 are same. Content Reference, because s1 and s3 are string class objects.
System.out.println("-----");
Thread t1 = new Thread();
Thread t2 = new Thread();
Thread t3 = t1;
String st1 = new String("WORLD");
String st2 = new String("WORLD");
System.out.println(t1 == t3); // true; Both t1 and t3 refer to same objects. Address of t1 is assigned to t3.
System.out.println(t1 == t2); //false; Addresses of t1 and t2 are different.
System.out.println(st1 == st2); // false; Addresses of st1 and st2 are different.
System.out.println(t1.equals(t2)); /* false; Here, t1 and t2 are both Thread class objects (not String class objects) and we haven't overridden the
.equals() method for Thread class anywhere so by default (as per point 4), .equals() of Object class will be
in effect and hence as per point 3, .equals() will be used as REFERNCE Comparison.
And since addresses are different, it's false.*/
System.out.println(st1.equals(st2)); /* true; Unlike above scenario, st1 and st2 are String class objects and hence as per point 5, content reference is
happening here and since their contents are same, it is true.*/
}
}
My confusion is that this t1.equals(t2) gives false because of which reason? Is it because the contents are not matching or reference comparison is happening here? I'm sure that the answer is Reference Comparison since I haven't overridden the .equals() method in my main class and by default it is using the method of the Object class (as stated in the statement at the very beginning).
But consider the below scenario too:
st1.equals(st2) is giving true because of which reason? Contents are matching? Is it not like reference comparison is happening here as well? Or, since contents are matching, it is not a reference comparison but a content comparison? Or, something else?
Please explain.

The String class overrides the equals method that is inherited from the Object class and implemented logic to compare the two String objects character by character.
Why you might ask, did the String class override the equals method inherited from the Object class? Because the equals method inherited from Object performs reference equality!
That's why when comparing two Strings using .equals() method, their content is compared, and not their references.
The evidence is provided by your code itself.
Here are two more pieces of evidence the String overrides the Object.equals(Object)
The Javadoc implies so. Notice that equality is based on the contents of the string. Indeed, even the existence of a distinct Javadoc for the String.equals(Object) method implies that the method has been overloaded ... given the way that javadocs are generated.
The source code says so. Clearly, the linked code is an overload. And clearly, it is not simply comparing object references.
Note
As commented, not all Strings in Java are interned. Try reading something from a file or console, those Strings aren't "interned", thus equals() (and also hashcode()) needs to be overridden.

Related

String pool memory alloaction

String s = "abc";
String s4 = s + "";
System.out.println(s4 == s);
System.out.println(s4.equals(s));
This prints:
false
true
Can anybody please explain why is it so?
String s="abc"; // goes to string constants pool
String s4 = s +"" ;// has value "abc" but goes on heap and not in string constants pool
System.out.println(s4==s);//well,, the references are not equal. There are 2 diffrent instances with value="abc"
System.out.println(s4.equals(s)); // equals() checks for value and the values of both insatnces are equal.
Here is your code with output in comment -
String s="abc";
String s4 = s +"" ;
System.out.println(s4==s); //false
System.out.println(s4.equals(s)); //true
First one is false because it is checking the reference of s4 and s. Since these two reference are different it evaluated to false. Here == (the equality) operator, when applied on reference type, is used to check whether two reference are same or different.
equals() is a method which is achieved by every reference type from object class. You can override the equals() method for your own class.
The equals(s) method is used to check whether the two object are meaningfully equals or not. For String class the meaningfully equals means the two comparing strings are same but their references may be different. String class has already override the equals()method and hence you need not override the equals() method by yourself.
Now for understanding string pool concept, consider the following code snippet -
String s5 = s;
System.out.println(s5); //abc
System.out.println(s5==s); //true
System.out.println(s5.equals(s)); //true
Here s5==s evaluated to true. Because s5 is not referencing a new String object. It's referencing the the existing String object (that is - "abc" referenced by s) in the string pool. Now the both reference s5 and s4 are equals. In the last statement s5 and s are meaningfully equals and hence s5.equals(s) evaluated to true.
Hope it will help.
Thanks a lot.

what does obj1 == obj2 actually compare

I am studying Overriding hashCode() and equals(Object obj) methods of Object class.
body of equals(Object obj) method in Object class is :
public boolean equals(Object obj) {
return (this == obj);
}
and hashCode() is native :
public native int hashCode();
I have a class Test with overrided equals(Object obj) and hashCoe() :
public class Test {
public static void main(String[] args){
Test t1 = new Test();
Test t2 = new Test();
System.out.println("t1 toString() : " + t1.toString());
System.out.println("t1, Hex value of hashcode : " + Integer.toHexString(t1.hashCode()));
System.out.println("t2 toString() : " + t2.toString());
System.out.println("t2, Hex value of hashcode : " + Integer.toHexString(t2.hashCode()));
System.out.println(t1.equals(t2));
}
#Override
public int hashCode() {
return 999; //hard coded value is just for testing
}
#Override
public boolean equals(Object obj) {
return (this == obj);
}
}
Output of my Code is :
t1 toString() : demo.Test#3e7
t1, Hex value of hashcode : 3e7
t2 toString() : demo.Test#3e7
t2, Hex value of hashcode : 3e7
false //why it is false
why equals(Object obj) returns false in this case if both objects toString() returns the same reference ID (hashcode) [I am not sure if it compares hashcode or not].
What does == operator actually compare in case of objects?
in this answer, answerer said that == that is, it returns true if and only if both variables refer to the same object, if their references are one and the same.
How does it know that the variables refer to the same object???
How does it know that the variables refer to the same object?
Because the values of the variables are the same references. (Your variables are t1 and t2. The values of those variables are references. Those references are used as a way of navigating to objects, basically.)
Suppose you and I both have pieces of paper with a house's street address on (that's my usual analogy for "variables with references"). How do we check whether they refer to the same house? We see whether the address is the same.
There are some potential twists here, as in some cases the form of the reference may not be the same between two expressions, but that's the basic idea.
(Note that just because I've used "address" in the analogy, that doesn't mean a Java reference is always a memory address. It's "a way of navigating to an object", that's all. It may or may not just be an address.)
From the JVM specification section 2.2:
The Java Virtual Machine contains explicit support for objects. An object is either a dynamically allocated class instance or an array. A reference to an object is considered to have Java Virtual Machine type reference. Values of type reference can be thought of as pointers to objects. More than one reference to an object may exist. Objects are always operated on, passed, and tested via values of type reference.
== will check if both references are the same. You have 2 different objects, no matter they are equivalent, they point to different memory blocks.
The only exception to this rule is String, in special conditions(i.e. invoking .intern() method), but that's really a special case, related to String pool.
If you compare with == equals, the instances of the Object needs to be the same (pointer to the same reference, "same id" in the JVM). The hashcode of the object is'nt checked.
This is why it is a good practice to compare with equals(..) in Java.
Here some code:
Test o1 = new Test();
Test o2 = new Test();
//You can check the ids with System#identityHashCode(Object):
System.out.println(System.identityHashCode(o1));
System.out.println(System.identityHashCode(o2));
o1 == o1 // will be true
o1 == o2 // will be false
o1.equals(o2) //depends on how you have implemented equals() and hashCode() in the Test Object.
The contract between hashCode and Equals is:
objects which are .equals() must have the same .hashCode()
The reverse statement does not need to be true.
In your example, it is exacly the case: you return 999 in .hashCode() and you compare the jvm ids in .equals().
== checks to see if the two objects refer to the same place in memory. In other words, it checks to see if the 2 object names are basically references to the same memory location
EX1:
String obj1 = new String("xyz");
String obj2 = new String("xyz");
obj1==obj2; //False
EX2
String obj1 = new String("xyz");
String obj2 = obj1;
obj1==obj2; //True

How many objects are created including String objects [duplicate]

This question already has answers here:
String equality vs equality of location
(6 answers)
What is the difference between == and equals() in Java?
(26 answers)
Closed 9 years ago.
Can anyone tell me how many objects are created. Does s3 not reference the same hello from string pool? how many String objects are there
/**
*
*/
package agnitio;
/**
* #author admin
*
*/
public class TestString {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1="hello";
String s2="hello";
String s3 = new String("hello");
System.out.println(s1==s2); // true
System.out.println(s1==s3); // false
System.out.println(s2==s3); // false
}
}
Only two objects are created. First object when you do :
String s1="hello";
No object is created in memory when you do :
String s2="hello";
This is because JVM String class is based on flyweight pattern so if a string already exist in memory as in your case "hello", so creating a new reference will not create a new object. Both s1 and s2 will point to the same memory location.
Second object is created when you do:
String s3 = new String("hello");
As new operator will always create a new object.
== compares whether both the references pointing to the same memory location or not. While equals compares the contents of strings. Having said that and as I mentioned both s1 and s2 are pointing to same memory location and hence both == and equals will return TRUE for their comparison. But s3 is a different object and hence comparison wiht s1 and s2 with == operation will return false. But if you do equals comparison of s1,s2 and s3, you will get TRUE.
No, imagine StringPool facility without making string immutable , its not possible at all because in case of string pool one string object/literal e.g. "hello" has referenced by many reference variables , so if any one of them change the value others will be automatically gets affected i.e. lets say
String A = "hello"
String B = "hello"
Now String B called "hello".toUpperCase() which change the same object into "TEST" , so A will also be "TEST" which is not desirable.
=====EDIT=====
If we are talking about how many string objects are there:
String s = "hello"; // one string object in the string pool "hello"
String s2 = "hello"; // two object variables (s, s2)
in this simple case, "abc" will go in the pool and s and s2 will refer to it.
String s3 = new String("hello"); // creates two objects, and one reference variable.
In this case, because we used the new keyword, Java will create a new String object
in a normal (nonpool) memory and s will refer to it. In addition the literal "hello"
will be placed in the pool as well (if it doesn't exist).
.equals() method matches two strings based on values (contents present) in that String and == check whether two objects points to same reference or not.
check the link below you will get your answer,
difference between == and equals method
use String.contentEquals:
"stringA".contentEquals("StringB");
Strings are objects, and whenever you create a 'new string' it actually creates a 'new String(value)' which points to a location in memory For example a "float" is a primitive/value, whereas Float is an Object with a pointer to a location in memory. When you use '==' it simply checks if the pointers are the same. "String.contentEquals" checks to see if the contents of both objects are the same.

How the equals() method works

I am digging into the basics of Java. I infer from this article, that the Java 'equals' method means, if two objects are equal then they must have the same hashCode().
Here's my example.
public class Equals {
/**
* #param args
*/
public static void main(String[] args) {
String a = new String("a");
String b = new String("a");
System.out.println("a.hashCode() "+a.hashCode());
System.out.println("b.hashCode() "+b.hashCode());
System.out.println(a == b);
System.out.println(a.equals(b));
}
}
Output:
a.hashCode() 97
b.hashCode() 97
false
true
The actual Java language 'equals' method:
public boolean equals(Object obj) {
return (this == obj);
}
In my above example, a.equals(b) has returned true, meaning the condition 'a==b' is satisfied. But then why is 'a==b' returning false in that example?
Aren't hashCode and address one and same? Also, is 'hashCode' compared when we say 'a==b' or something else?
The String class has overridden the equals() method. Please follow the String equals() documentation.
a.equals(b) has returned true, meaning the condition a==b is satisfied
This is the default implementation of equals() in the Object class, and the String class has overridden the default implementation. It returns true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
Aren't hashCode and address one and same?
Not necessarily. For further reading on hashCode().
The == operator in Java compares object references to see if they refer to the same object. Because your variables a and b refer to different objects, they are not equal according to ==.
And the hashCode method doesn't return the address in String, because that class has overridden hashCode.
Additionally, the equals method has been implemented in String to compare the contents of the strings; that's why a.equals(b) returns true here.
No, Hashcode and address aren't the same.
Because a==b is not comparing hashcodes.
Yes, something else is compared when we say a==b.
(that's not addresses either, really, but it's close enough).
Also, just because "equal objects have equal hashcodes" does not mean "equal hashcodes means equal objects".
a.equals(b) is different from a==b.
a.equals(b) checks if two objects are equals based on equals() implementation.
a==b checks if two objects have same reference.
If a==b is true then a.equals(b) must be true because they are referencing to the same object but not vice-versa.
String class overrides the default implementation of the equals() method of the Object class. The equals method code that you have provided is not from String class but from the Object class, which is overridden be the String class implementation which checks if the contents of the two objects are same or not.
Hashcode for an object is meant to be overridden.
For String class the formula used is as follows:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
I encourage you to search why 31 has been used as a multiplier and not some other number.
A general thumb rule for overriding hash code is that for different objects hash code should be different as far as possible.
To achieve this it is advisable that you take into account every significant field of an object while calculating the hash value.
Note: Just an unrelated food for thought (source : Effective Java):
Consider the following implementation of hashcode
int hashcode(){
return 10;
}
This is a valid implementation but it is also the worst possible one. Read about why.
A and B are two separate objects that generate the same hash code because of String's implementation of hashCode(). == just checks to see if the left and right sides share the same reference. It does not call an Object's equals() method.
So, no, hashes and object references are not the same thing.
public class TestEquals {
/**
* #param args
*/
public static void main(String[] args) {
String a = new String("a");
String b = new String("a");
System.out.println("a.hashCode() " + a.hashCode());
System.out.println("b.hashCode() " + b.hashCode());
// Checks the reference which is something like the
// address & address is different from hash code which can be overriden
System.out.println(a == b);
// It returns true if and only if the argument is not null
// and is a String object that represents the same sequence
// of characters as this object. (String Implementation of equals)
System.out.println(a.equals(b));
}
}
Output:
a.hashCode() 97
b.hashCode() 97
false
true

Regarding the role of intern() method

I have made the code but please tell the functionality of the intern() method of String class , does it try to bring the pool object address and memory address on the same page?
I have developed the below code :
public class MyClass
{
static String s1 = "I am unique!";
public static void main(String args[])
{
String s2 = "I am unique!";
String s3 = new String(s1).intern();// if intern method
is removed then there will be difference
// String s3= new String("I am unique!").intern();
System.out.println("s1 hashcode -->"+s1.hashCode());
System.out.println("s3 hashcode -->"+s3.hashCode());
System.out.println("s2 hashcode -->"+s2.hashCode());
System.out.println(s1 == s2);
System.out.println("s1.equals(s2) -->"+s1.equals(s2));
/* System.out.println("s1.equals(s3) -->"+s1.equals(s3));
System.out.println(s1 == s3);
System.out.println(s3 == s1);
System.out.println("s3-->"+s3.hashCode());*/
// System.out.println(s3.equals(s1));
}
}
Now what's the role of the above intern() method?
As the hashCodes() are the sames, please explain the role of intern() method.
Thanks in advance.
Since operator== checks for identity, and not equality, System.out.println(s1 == s3); (which is commented out) will yield true only if s1 and s3 are the exact same objects.
The method intern() makes sure that happens, since the two strings - s1 and s3 equal each other, by assigning their intern() value, you make sure they are actually the same objects, and not two different though equal objects.
as the javadocs say:
It follows that for any two strings s and t, s.intern() == t.intern()
is true if and only if s.equals(t) is true.
p.s. you do not invoke intern() on s1, because it is a String literal - and thus already canonical.
However, it has no affect on s1 == s2, since they are both string literals, and intern() is not invoked on neither of them.
From the String.intern() Javadoc
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java™ Language Specification.
Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.
Do you have a more specific doubt which is not covered by the Javadoc?
.intern() ensures that only one copy of the unique String is stored. So, multiple references to the same interned String will result in the same hashCode() as the hashing is being applied to the same String.
This method returns a canonical representation for the string object. It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
Returns a canonical representation for the string object.
refer http://www.tutorialspoint.com/java/java_string_intern.htm
If you call the intern method of this String object,
str = str.intern();
The JVM will check whether the String pool maintained by the JVM contains any String objects with the same value as the str object with the equals method returning true.
If the JVM finds such an object, then the JVM will return a reference to that object present in the String pool.
If no object equal to the current object is present in the String pool, then the JVM adds this string into the String pool and returns its reference to the calling object.
The JVM adds the object to the String pool so that the next time when any string object calls the intern method, space optimization can be done if both of these strings are equal in value.
You can check the working of intern method using the equals and == operators.
refer : http://java-antony.blogspot.in/2007/07/string-and-its-intern-method.html
String.intern() canonicalize strings in an internal VM string pool. It ensure that there is only one unique String object for every different sequence of characters. Then those strings can be compare by identity (with operator ==), instead of equality (equals()).
For example :
public class Intern{
public static void main(String[]args){
System.out.println(args[0].equals("")); //True if no arguments
System.out.println(args[0] == ""); //false since there are not identical object
System.out.println(args[0].intern() == ""); //True (if there are not multiple string tables - possible in older jdk)
}
}
So, if two Strings are equals (s1.equals(s2) is true) then s1.intern() == s2.intern() is true.

Categories