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)
Related
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!
This may not be the real world scenario but just curious to know what happens, below is the code.
I am creating a set of object of class UsingSet.
According to hashing concept in Java, when I first add object which contains "a", it will create a bucket with hashcode 97 and put the object inside it.
Again when it encounters an object with "a", it will call the overridden hashcode method in the class UsingSet and it will get hashcode 97 so what is next?
As I have not overridden equals method, the default implementation will return false. So where will be the Object with value "a" be kept, in the same bucket where the previous object with hashcode 97 kept? or will it create new bucket?
anybody know how it will be stored internally?
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
class UsingSet {
String value;
public UsingSet(String value){
this.value = value;
}
public String toString() {
return value;
}
public int hashCode() {
int hash = value.hashCode();
System.out.println("hashcode called" + hash);
return hash;
}
public static void main(String args[]) {
java.util.Set s = new java.util.HashSet();
s.add(new UsingSet("A"));
s.add(new UsingSet("b"));
s.add(new UsingSet("a"));
s.add(new UsingSet("b"));
s.add(new UsingSet("a"));
s.add(new Integer(1));
s.add(new Integer(1));
System.out.println("s = " + s);
}
}
output is:
hashcode called65
hashcode called98
hashcode called97
hashcode called98
hashcode called97
s = [1, b, b, A, a, a]
HashCode & Equals methods
Only Override HashCode, Use the default Equals:
Only the references to the same object will return true. In other words, those objects you expected to be equal will not be equal by calling the equals method.
Only Override Equals, Use the default HashCode: There might be duplicates in the HashMap or HashSet. We write the equals method and expect{"abc", "ABC"} to be equals. However, when using a HashMap, they might appear in different buckets, thus the contains() method will not detect them each other.
James Large answer is incorrect, or rather misleading (and part incorrect as well). I will explain.
If two objects are equal according to their equals() method, they must also have the same hash code.
If two objects have the same hash code, they do NOT have to be equal too.
Here is the actual wording from the java.util.Object documentation:
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.
It is true, that if two objects don't have the same hash then they are not equal. However, hashing is not a way to check equality - so it is wildly incorrect to say that it is a faster way to check equality.
Also, it is also wildly incorrect to say the hashCode function is an efficient way to do anything. This is all up to implementation, but the default implementation for hashCode of a string is very inefficient as the String gets large. It will perform a calculation based on each char of the String, so if you are using large Strings as keys, then this becomes very inefficient; moreso if you have a large number of buckets.
In a Map (HashSet uses a HashMap internally), there are buckets and in each bucket is a linked list. Java uses the hashCode() function to find out which bucket it belongs in (it actually will modify the hash, depending on how many buckets exist). Since two objects may share the same hash, it will iterate through the linked list sequentially next, checking the equals() method to see if the object is a duplicate. Per the java.util.Set documenation:
A collection that contains no duplicate elements.
So, if its hashCode() leads it to a bucket, in which that bucket contains an Object where the .equals() evaluates to true, then the previous Object is overwritten with the new Object. You can probably view here for more information:
How does a Java HashMap handle different objects with the same hash code?
Generally speaking though, it is good practice that if you overwrite the hashCode function, you also overwrite the equals function (if I'm not mistaken, this breaks the contract if you choose not to).
Simply you can Assume hashcode and equals methods as a 2D search like:-
Where Hashcode is the Rows and the object list is the Column.
Consider the following class structure.
public class obj
{
int Id;
String name;
public obj(String name,int id)
{
this.id=id;
this.name=name;
}
}
now if you create the objects like this:-
obj obj1=new obj("Hassu",1);
obj obj2=new obj("Hoor",2);
obj obj3=new obj("Heniel",3);
obj obj4=new obj("Hameed",4);
obj obj5=new obj("Hassu",1);
and you place this objects in map like this :-
HashMap hMap=new HashMap();
1. hMap.put(obj1,"value1");
2. hMap.put(obj2,"value2");
3. hMap.put(obj3,"value3");
4. hMap.put(obj4,"value4");
5. hMap.put(obj5,"value5");
now if you have not override the hashcode and equals then after putting all the objects till line 5 if you put obj5 in the map as By Default HashCode you get different hashCode so the row(Bucket will be different).
So in runtime memory it will be stored like this.
|hashcode | Objects
|-----------| ---------
|000562 | obj1
|000552 | obj2
|000588 | obj3
|000546 | obj4
|000501 | obj5
Now if you create the same object Like :-
obj obj6 = new obj("hassu",1);
And if you search for this value in the map.like
if(hMap.conaints(obj6))
or
hMpa.get(obj 6);
though the key(obj1) with the same content is available you will get false and null respectively.
Now if you override only equals method.
and perform the same content search key will also get the Null as the HashCode for obj6 is different and in that hashcode you wont find any key.
Now if you override only hashCode method.
You will get the same bucket (HashCode row) but the content cant be checked and it will take the reference checked implementation by Super Object Class.
SO here if you search for the key hMap.get(obj6) you will get the correct hashcode:- 000562 but as the reference for both obj1 and obj6 is different you will get null.
Set will behave differently.
Uniqueness wont happen. Because unique will be achieved by both hashcode and equals methods.
output will be liked this s = [A, a, b, 1] instead of early one.
Apart that remove and contains all wont work.
Without looking at your code...
The whole point of hash codes is to speed up the process of testing two objects for equality. It can be costly to test whether two large, complex objects are equal, but it is trivially easy to compare their hash codes, and hash codes can be pre-computed.
The rule is: If two objects don't have the same hash code, that means they are not equal. No need to do the expensive equality test.
So, the answer to the question in your title: If you define an equals() method that says object A is equal to object B, and you define a hashCode() method that says object A is not equal to object B (i.e., it says they have different hash codes), and then you hand those two objects to some library that cares whether they are equal or not (e.g., if you put them in a hash table), then the behavior of the library is going to be undefined (i.e., probably wrong).
Added information: Wow! I really missed seeing the forest for the trees here---thinking about the purpose of hashCode() without putting it in the context of HashMap. If m is a Map with N entries, and k is a key; what is the purpose of calling m.get(k)? The purpose, obviously, is to search the map for an entry whose key is equal to k.
What if hash codes and hash maps had not been invented? Well the best you could do, assuming that the keys have a natural, total order, is to search a TreeMap, comparing the given key for equality with O(log(N)) other keys. In the worst case, where the keys have no order, you would have to compare the given key for equality with every key in the map until you either find a match or tested them all. In other words, the complexity of m.get(k) would be O(N).
When m is a HashMap, the complexity of m.get(k) is O(1), whether the keys can be ordered or not.
So, I messed up by saying that the point of hash codes was to speed up the process of testing two objects for equality. It's really about testing an object for equality with a whole collection of other objects. That's where comparing hash codes doesn't just help a little; It helps by orders of magnitude...
...If the k.hashCode() and k.equals(o) methods obey the rule: j.hashCode()!=k.hashCode() implies !j.equals(k).
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.
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.
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.