Example of ==, equals and hashcode in java - java

Given this:
String s1= new String("abc");
String s2= new String("abc");
String s3 ="abc";
System.out.println(s1==s3);
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
Output is:
false
false
true
true
96354
96354
96354
Here == is giving false for each object but the hashcode for each String object is same. Why is it so?

== does compare real equality of objects (I mean - both references point to the same object), not their content, whereas .equal compares content (at least for String).
String a = new String("aa");
String b = new String("aa");
a and b are pointing to different objects.
Notice also that if objects are equal then their hashchodes must be the same, but if hashcodes are the same, it doesn't mean that objects are equal.

The equals contract says that if o1.equals(o2), then o1.hashCode() == o2.hashCode(). It doesn't specify anything about the hash codes of unequal objects. You could have a method like
public int hashCode()
{
return 42;
}
and it'd fulfill the contract. It's just expected that the hash code be related to the value of the object, in order to make hash tables work more efficiently.
Now, as for why your == doesn't work, two objects will always be compared by reference. That is, if o1 == o2, then o1 and o2 are the exact same object. That's rarely what you want; you usually want to see if o1.equals(o2) instead.

When you use ==, you are comparing if two variables hold reference to the same Object. In other words s1 == s2 is like asking: are the s1 and s2 variables referring to the same String object? And that's not true, even when both String objects have the same "abc" value.
When you use equals(), you are comparing the value of both objects. Both objects may not be the same, but their value (in this case "abc") is the same, so it returns true.
How do you define whether an object is equal to another? That's up to you. In this case the String object already defines this for you, but for example if you define a Person object, how do you know if a person P1 is equal to P2? You do that by overriding equals() and hashCode().

== tells you whether the two variable references point at the same object in memory, nothing more. equals() and hashCode() both look at the contents of the object and each uses its own algorithm for calculation.

Related

Does newBuilder() from Protobuf generated classes create a new Java object?

Does newBuilder() creates a new Java object? It doesn't seem like to be the case for my quick test. Calling .hashcode() on 2 different objects, it has the same hash code.
import com.mydomain.proto.users.api.User;
...
User a = User.newBuilder().setUserUuid("1111111111").build();
User b = User.newBuilder().setUserUuid("1111111111").build();
System.out.println("a hashcode: " + a.hashCode());
System.out.println("b hashcode: " + b.hashCode());
// assertNotEquals fails.
assertNotEquals(a.hashCode(), b.hashCode());
Printing them out and see that the hash code is the same, though I am expecting a new Java object.
a hashcode: 611667980
b hashcode: 611667980
Note, we are using this
'com.google.protobuf:protobuf-java-util:3.12.0'
The implication of the hashcode and same (==) is not bidirectional.
Two objects that are the same object, or own the same contents, should have the same hashcode.
Two objects sharing the same hashcode doesn't imply they're the same object.
In order to test this, check
System.out.println(a==b);
It will print false, because they are different Objects, even if they share the same hashcode.
Source code for Message:
Equals check first if the objects are indeed the same (==) . If not, checks if their fields and properties contain the same values.
Hashcode will output the same value if two objects contain the same properties and fields. Regardless they're the same object (other==this) or not. Just like Strings do.
This is what Java Object's hashCode() tells:
Example with Strings
String s1 = new String("Yepp"); //hashcode = 2752044
String s2 = new String("Yepp"); //hashcode = 2752044
String s3 = s1; //hashcode = 2752044
All share the same hashcode. But there are two different Objects here:
s1/s3 and s2.
System.out.println(s1==s2); // false
System.out.println(s1==s3); // true
System.out.println(s1.hashCode()==s2.hashCode()); //true
That's why is an usual mistake comparing two strings with the == operator. This is not checking the values, but the object reference.
If the class overrides equals, (as Strings do), it will tell you they're equal objects: Equal as twins may be, but twins are two anyway.
System.out.println(s1.equals(s2)); // true
Resume: Yes, it's creating new objects. The values inside are meaningless, and sharing the same hashcode only means they both have the same contents (and that their hashcode algorithm works well)

String interning and HashSet in java

I have read about string interning, in which String literals are reused, whereas String object created using new aren't reused. This can be seen below when I print true and false for their equality. To be specific, (p1==p2)!=p3, So there are two objects, one pointed by p1 and p2 and another by p3. However, when I add them to HashSet, all considered same. I was expecting a.size() to return 2, but it returned 1. Why is this so?
package collections;
import java.util.HashSet;
public class Col {
public static void main(String[] args) {
method1();
}
public static void method1()
{
HashSet a = new HashSet();
String p1 = "Person1";
String p2 = "Person1";
String p3 = new String("Person1");
if(p1 == p2)
System.out.println(true);
else
System.out.println(false);
if(p1 == p3)
System.out.println(true);
else
System.out.println(false);
a.add(p1);
a.add(p2);
a.add(p3);
System.out.println(a.size());
}
}
Output
true
false
1
HashSet uses equality to keep a unique set of values, not identity (i.e., if two objects are equals to each other, but not ==, a HashSet will only keep one of them).
You can implement a set that uses identity instead of equality by using the JDK's IdentityHashMap with a dummy value shared between all keys, in a similar way that HashSet is based on HashMap.
I have read about string interning, in which String literals are reused, whereas String object created using new aren't reused. This can be seen below when I print true and false for their equality. To be specific, (p1==p2)!=p3, So there are two objects, one pointed by p1 and p2 and another by p3. However, when I add them to HashSet, all considered same. I was expecting a.size() to return 2, but it returned 1.
This is right only if you compare String using ==, the result is different when comparing using equals() method. (In doubt, you can test).
When adding into HashSet, the comparison method used is equals() as its proper for objects. And so, p1, p2 and p3 are equals.
You can try testing using equals() it will output true, true, 1 instead of true, false, 1
p1 and p2 are string literals and they are pointing to the same value because of string pool. So, when we are comparing them using == then they are matching.
p3 is a string object, so when we match using == then it tries to match using reference, so it gives false.
HashSet's add method call HashMap's put method internally. HashMap's put method use hashCode and equals method to set the value in HashMap. String implement hashCode and equals method and provide same hashCode for same value. HashSet contain unique value, so it store only one value.
This is one of those cases where I would recommend learning how to use javap to understand how your code is compiled but let me try to explain what is going on under the hood.
When Java compiles that class, it creates instructions for building what is called the constant pool for that class. That constant pool will hold a reference to a string with the value "Person1". The compiled logic will also say p1 and p2's value should be set to the constant pool's reference to that string (the address in memory that it lives in). Calling p1==p2 will return true because they literally have the same exact value. When you call String p3 = new String("Person1"); you are telling Java to create a new string in a different place in memory which is merely a copy of the original one and then set p3's value as a reference to the place in memory that the new string object lives in. So if you call p1 == p3 it will return false because what you are saying is "does p1's location in memory equals p2's location in memory?"
As others have pointed out, if you called p1.equals(p3) it returns true because .equals compares the string values instead of the references. And a HashSet will see them all the same because it uses the method .hashCode which is similar to .equals in the sense that it generates a hash off of the string value.
Hopefully that clears up some of the confusion!

Understanding String and equals [duplicate]

This question already has answers here:
Test of equality (equals and hash code method)
(6 answers)
Closed 9 years ago.
When using String s1="java"; and String s2= new String("java");
do both of these create different String objects? I know if I use String s3="java" it uses the same object of s1 but in s2 case also does it use same object? If so then why does StringBuffer sb = new StringBuffer("java"); use a different object. Because if i do System.out.println(sb.equals( s1 )); it returns false;
My understanding of equals method is that it compares if both the references refer to same object unless we have overridden equals method , please let me know if my understanding is wrong.
does both of these create different String object
There are two aspects here. First one is interning of String literals. Out of these two statements:
String s1 = "Hello";
String s2 = new String("Hello");
First one will use the literal string "Hello" that is already in the constant pool. If it isn't there, it will create an entry in the constant pool for "Hello" (In which case you can say that, an object is created)
In 2nd case, you have 2 string objects - first one is the string literal "Hello", which will be interned from the constant pool, and then the 2nd object creation is due to the use of new keyword - new String(...) will certainly create a new object. So:
s1 == s2; // This will return `false`
because, s1 and s2 are reference to 2 different String objects.
Now comes your 2nd case:
String s1 = "Hello";
StringBuffer sb = new StringBuffer("Hello");
In 2nd statement, you are creating a new StringBuffer object. Well, firstly a StringBuffer is not a String. Secondly, since StringBuffer class does not override equals() method, so when you invoke equals method like this:
sb.equals(s1);
it will invoke the Object#equals() method, which does comparison based on the value of reference. So, it will return false, since sb and s1 are pointing to 2 different instance.
However, if you compare them like this:
sb.toString().equals(s1);
then you will get true now. Since String class has overridden the equals() method, which does the comparison based on the contents.
See also:
What is the difference between String and StringBuffer in Java?
How do I compare strings in Java?
Your understanding of the equals method is wrong. It is the == operator that does what you are describing.
The equal method is implemented to do this (quoted from the String class documentation) :
"The result is 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 s1="java";
At this point, s1 points to a String object.
String s2 = new String("java");
String has already overridden the equals method, to check for the contents of the object, as per the documentation.
SO s1.equals(s2) will evaluate to true, because they have the same contents.
Object.equals() will check if the two objects are the same.
String s1="java"; and String s2= new String("java"); does both of
these create different String object
new always creates a new object. That said, the internal string they're referring to is the same. In this case == will return false but equals will return true.
if so then why does StringBuffer sb = new StringBuffer("java"); use
different object
StringBuffer is not String. They're 2 totally different classes. It's the same as comparing String with Integer. Maybe you meant System.out.println(sb.toString().equals( s1 ));?
My understanding of equals method is that it comparse if both the
reference refer to same object unless we have overridden equals method
You're right, but in this case, String overrides equals() (and hashcode() as well) so the behavior is not that of Object#equals().
Ok, let use an analogy.
If I write the same word like 'HELLO' on two pieces of paper.
Then I bring in a panel of experts and ask them some questions.
Q. Expert one. Are those two things the same?
A. Yes they are the same, it says HELLO.
Q. Expert two, make me a paper airplane out of a piece of paper.
A. Ok, sure.
Q. Expert three, are these two things the same?
A. Of course not, one is a paper airplane.
Q. Expert four, get another sheet and write 'HELLO' on it. Now at all these things the same?
A. Of course, they all say 'HELLO'
So, it depends what you mean by equals.
And computer languages have some non intuitive ways of defining equals.
Sometimes equals means we care about the words on the paper, sometimes we are concerned that it the exact same piece of paper' which doesn't matter a lot of the time, as long as they both say 'HELLO'
s1 and s3 refer to the same object but s2 is another different object in memory. check out http://www.journaldev.com/797/what-is-java-string-pool the image and explanations at that link will clarify it more than words can.

How and what does "==" operator in java check?

I have been stuck with this for a while now, Actually I have 2 objects which according to me are same, I have overriden the hashCode method to create equal hash codes for both, still when I compare them for equality using "==" or Object's equals(which too uses "=="), it returns false to me, The below scenario should exactly explain:::
1)HashCode-->-626561382 AND 2)HashCode--->-626561382
1)IdentityHashCode-->19640463
2)IdentityHashCode-->22330755
1)Bean1=beans.OrdersBean#daa76e9a AND 2)Bean2=beans.OrdersBean#daa76e9a
Check MySelf for(==)-->false
Check Object's Equals()-->false
Please kindly explain me why is this happening????
== operator compare refrences(Memory location) of Objects in java...
if you compare objects then use .equals()
if(obj1.equals(obj2)){
}
See here
To compare two objects for equal value you need to override the equals method.
The == operator as others have mentioned compares references (i.e. is it the exact same object)
Explanation
If you take the example of identical twins Ben and Adam, using an == would return false when comparing the two since Ben is not Adam (even though they look the same), if you use .equals and the comparison is based on looks then this would return true.
In Java == is used to compare reference. To valuate if two objects are equivalent use equals.
Note If you have to compare custom objects consider ovverriding equals in your class according to your equivalence criteria.
Override .equals from the parent Object's method, this is intended for "deeper" comparisons whereas == pertains to checking that the references (identifiers) are referring to (so that updates to one apply to both) the same instantiation.
1. Using '==' :
When you want to check if two reference variables are referring to a same object you should use == operator in java. For example - (Assume there is a class called Person)
Person person1 = new Person();
Person person2 = person1;
System.out.println(person1 == person2); // true
Here as we have used new only once, only one object is getting created in the heap memory and we are assigning it to a reference variable -> person1. In the second statement we are assigning person1 to person2. So actually there is only one object in memory but both person1 and person2 are referring to the same object.
[In short we can say that, similar to primitives, == compares the value in the variable which in case of reference variables is memory address of the actual object].
2. Using '.equals()' :
When you want to check if the two objects are meaningfully equal then use .equals() method. For example -
Person person1 = new Person();
Person person2 = new Person();
System.out.println(person1.equals(person2)); // false
Here we are creating altogether two different objects, so they are not meaningfully equal. Hence the equals() method will return false.

Java hashCode doubt

I have this program:
import java.util.*;
public class test {
private String s;
public test(String s) { this.s = s; }
public static void main(String[] args) {
HashSet<Object> hs = new HashSet<Object>();
test ws1 = new test("foo");
test ws2 = new test("foo");
String s1 = new String("foo");
String s2 = new String("foo");
hs.add(ws1);
hs.add(ws2);
hs.add(s1);
hs.add(s2); // removing this line also gives same output.
System.out.println(hs.size());
}
}
Note that this is not a homework. We were asked this question on our quiz earlier today. I know the answers but trying to understand why it is so.
The above program gives 3 as output.
Can anyone please explain why that is?
I think (not sure):
The java.lang.String class overrides the hashCode method from java.lang.Object. So the String objects with value "foo" will be treated as duplicates. The test class does not override the hashCode method and ends up using the java.lang.Object version and this version always returns a different hashcode for every object, so the two test objects being added are treated as different.
In this case it's not about hashCode() but is about equals() method. HashSet is still Set, which has semantic of not allowing duplicates. Duplicates are checked for using equals() method which in case of String will return true
However for your test class equals() method is not defined and it will use the default implementation from Object which will return true only when both references are to the same instance.
Method hashCode() is used not to check if objects should be treated as same but as a way to distribute them in collections based on hash functions. It's absolutely possible that for two objects this method will return same value while equals() will return false.
P.S. hashCode implementation of Object doesn't guarantee uniqueness of values. It's easy to check using simple loop.
Hashcode is used to narrow down the search result. When we try to insert any key in HashMap first it checks whether any other object present with same hashcode and if yes then it checks for the equals() method. If two objects are same then HashMap will not add that key instead it will replace the old value by new one.
In fact, it is not about overriding the hashcode(), it is about equals method. Set does not allow duplicates. A duplicate is the one where the objects are logically equal.
For verifying you can try with
System.out.println(ws1.equals(ws2));
System.out.println(s1.equals(s2));
If the objects are equal, only one will be accepted by a set.
Below are few (well quite many) bullets refarding the equals and hashcode from my preparations to SCJP.
Hope it helps:
equals(), hashCode(), and toString() are public.
Override toString() so that System.out.println() or other methods can see something useful, like your object's state.
Use == to determine if two reference variables refer to the same object.
Use equals() to determine if two objects are meaningfully equivalent.
If you don't override equals(), your objects won't be useful hashing keys.
If you don't override equals(), different objects can't be considered equal.
Strings and wrappers override equals() and make good hashing keys.
When overriding equals(), use the instanceof operator to be sure you're evaluating an appropriate class.
When overriding equals(), compare the objects' significant attributes.
Highlights of the equals() contract:
a. Reflexive: x.equals(x) is true.
b. Symmetric: If x.equals(y) is true, then y.equals(x) must be true.
c. Transitive: If x.equals(y) is true, and y.equals(z) is true, then z.equals(x) is true.
d. Consistent: Multiple calls to x.equals(y) will return the same result.
e. Null: If x is not null, then x.equals(null) is false.
f. If x.equals(y) is true, then x.hashCode() == y.hashCode() is true.
If you override equals(), override hashCode().
HashMap, HashSet, Hashtable, LinkedHashMap, & LinkedHashSet use hashing.
An appropriate hashCode() override sticks to the hashCode() contract.
An efficient hashCode() override distributes keys evenly across its buckets.
An overridden equals() must be at least as precise as its hashCode() mate.
To reiterate: if two objects are equal, their hashcodes must be equal.
It's legal for a hashCode() method to return the same value for all instances (although in practice it's very inefficient).
In addition if you implement equals and hashcode the transient fields (if any) must be treated properly.
The Commons have nice implementation for EqualsBuilder and HashcodeBuilder. They are available in Coomons Lang
http://commons.apache.org/lang/
I use them whenevr I need to implement the equals and the hashcode.

Categories