In the below code different three outputs are coming depending upon the hashcode value generated for the object after running multiple times
Output1
collection.A#1
0
collection.A#0
0
true
Output2
collection.A#1
0
collection.A#0
1
true
Output3
collection.A#1
1
collection.A#1
1
true
I am not able to understand the three different outputs that are coming ,
For e.g Output3 why two objects are added if the hashcode is same of them and equals returns true
Simliarly I am not able to understand the Output1 & 2
public class A {
#Override
public int hashCode() {
long l=Math.round(Math.random());
return (int)l;
}
#Override
public boolean equals(Object arg0) {
return true;
}
public static void main(String args[]){
Set<A> h=new HashSet<A>();
for(int i=0;i<100;i++)
h.add(new A());
for (A a : h) {
System.out.println(a);
System.out.println(a.hashCode());
}
System.out.println(h.contains(new A()));
}
}
Basically, your code breaks the contract of hashCode().
One of the rules to implement hashCode is that this must always be true:
obj.hashCode() == obj.hashCode()
But in your case, this isn't. Every time hashCode is called, the result can be different from that of the previous call. This is because Math.random() returns a different value each time.
How come only two objects are added to the set?
Because only objects with different hash codes can be added to a HashSet. If an object with a hash code of 1 is added, another object with hash code of 1 cannot be added.
And since your hashCode method can only return two different integers - 1 and 0, at most 2 objects can be added.
In output 3, why do I see two objects of the same hash code in the set?
collection.A#1
1
collection.A#1
1
true
That is because your hashCode method may return different values every time you call it. Maybe when the two objects are added to the set, their hashCode method return different values. But by the time you call it, they change to the same value.
Anything can happen, ya know!
P.S. I hope this is not production code...
For e.g Output3 why two objects are added if the hashcode is same
Since the hashcode can be different each time you check it the strangeness of the results are to be expected.
If all 100 objects return the same hashcode (pairwise) when they are inserted then the set will contain only one object. The probability of this is 0.5^99 or almost 0.
When you print the result, you generate new hashcodes. The value you print is independent of the values used in the comparisons during insertion.
Try remembering the generated hashcode value in a field and have each object return the same value each time and the result will be the same every time.
Because your Math.round(Math.random()); always return 0 or 1. If you need larger range of random values, It should be like Math.round(Math.random()*10000);
You have to override toString() method as well in the Class A.
Add following method to Class A, or can modify it as your own.
#Override
public String toString() {
return "Class A";
}
Also change your hashCode() method as follows and try.
#Override
public int hashCode() {
long l=Math.round(Math.random()*10000);
return (int)l;
}
bcoz of Math.random()
The Math.random() returns a pseudorandom double greater than or equal to 0.0 and less than 1.0
Related
I have a set with two distinct objects added to it. After insertion, I change one of the objects in such a way that both the objects are equal (as verified by the overridden equals method in object class). At this point in time I have two duplicate elements in a set. Now I try to add these two duplicate objects in a new set and I am still able to add them even though the equals method returns true for them. Below is the code for the same. Can someone please tell me what exactly am I missing?
public class BasicSetImpl{
public int num; String entry;
public BasicSetImpl(int num, String entry){
this.num = num;
this.entry = entry;
}
#Override
public int hashCode() {
return Objects.hash(entry, num);
}
#Override
public boolean equals(Object obj) {
BasicSetImpl newObj = (BasicSetImpl)obj;
if (this.num == newObj.num)
return true;
else
return false;
}
public static void main(String[] args){
Set<BasicSetImpl> set = new HashSet<>();
BasicSetImpl k1 = new BasicSetImpl(1, "One");
BasicSetImpl k2 = new BasicSetImpl(2, "Two");
set.add(k1);
set.add(k2);
k2.num = 1;
System.out.println(k1.equals(k2)); //This line returns True
Set<BasicSetImpl> newSet = new HashSet<>();
newSet.add(k1);
newSet.add(k2);
//Set.size here is two
The hash based collection, in this case the HashSet uses the Object hashCode method to calculate the hash value as a function of contents of the object. Since you consider both the entry and num to determine the hashcode value of the object, these two objects has distinct hashcodes since they are different from entry. Thus they belong in two different hash buckets and never be recognized as the same.
However, if you set the entry as follows
k2.entry = "One";
then both k1 and k2 has the same hashcode value. Then they both belong to the same hash bucket and according to the equals method two objects are the same. Therefore, now the duplicates are ignored.
But, there's a problem lurking here. Ideally, equal objects must have equal hash codes. But, in your case it is not. Two objects are equal if they have the same num value, but they may produce different hashcode values. So the correct solution would be to just change your hashCode as follows.
#Override
public int hashCode() {
return Integer.hashCode(num);
}
Now, it should behave the way you would expect without the hack we added by setting k2.entry = "One";
hashCode and equals methods must be consistent.
From 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.
In your case despite they are equal their hashCodes are different.
When adding elements HashSet check hashe of the added object and only if there is existing object in set with the same hash, HashSet checks if these objects with same hashes are equal.
In this code I have declared a Initialized a String variable and then printed its hashcode, then reinitialized it to another value and then invoked the Garbage Collector to clear the dereferenced objects.
But when I reinitialize the String variable to its original value and print the hashcode, the same hashcode is getting printed. How?
public class TestGarbage1 {
public static void main(String args[]) {
String m = "JAVA";
System.out.println(m.hashCode());
m = "java";
System.gc();
System.out.println(m.hashCode());
m = "JAVA";
System.out.println(m.hashCode());
}
}
Hash code relates to object equality, not identity.
a.equals(b) implies a.hashCode() == b.hashCode()
(Provided the two methods have been implemented consistently)
Even if a gc were actually taking place here (and you weren't simply referencing strings in the constant pool), you wouldn't expect two string instances with the same sequence of chars not to be equal - hence, their hash codes will also be the same.
String a = new String("whatever");
String b = new String(a);
System.out.println(a == b); // false, they are not the same instance
System.out.println(a.equals(b)); // true, they represent the same string
System.out.println(a.hashCode() == b.hashCode()); // true, they represent the same string
I think you are misunderstanding something about how hashcodes work. Without going in to too much detail, in Java, hashcodes are used for many things. One example is used to find an item in a Hash datastructure like HashMap or HashSet.
A hash of the same value should always return the same hash. In this case, a hash of "JAVA" should never change because then it will break the agreement set forth in Java.
I think it's too complicated to go about how hashcodes for String are calculated. You can read more about it here. I can give you an example though.
Let's say you have a class Fruit and it has fields like shape, color and weight.
You must implement equals AND hashcode for this class. It is very important to do both because otherwise you are breaking the way Hashmap work. Let's say you make this for your hashCode() method.
#Override
public int hashCode() {
int hash = 1;
hash = hash * 17 + this.color;
hash = hash * 31 + this.shape.hashCode();
hash = hash * 31 + this.weight;
return hash;
}
This will generate the same hash value EVERY TIME for the two Fruit instances that are equal. That is exactly what you would want.
Really quick, how would this be actually used in a HashMap? Let's say you want to see if you have foo = new Fruit(); HashMap first calculates foo.hashCode(). It checks to see if there is anything in the bucket for that hashCode. If there is then it will use the equals() method until it returns true. It must do this because there might be hashcode collisions. And that's why it is important why equals and hashCode should be implemented together.
I read About System.identityHashCode(Object x). You can not override it because its static method but i can override Object's hashCode method. and also this is mentioned for System.identityHashCode(Object x) in javadoc as :
Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides
hashCode().The hash code for the null reference is zero.
but when i am running below code by swapping the object in println method i am getting same result.
public class SherlockGCD {
public int hashCode()
{
return super.hashCode();
}
public static void main(String[] args) {
SherlockGCD sher= new SherlockGCD();
SherlockGCD sher1= new SherlockGCD();
System.out.println(System.identityHashCode(sher));
System.out.println(sher1.hashCode());
}
}
Output is :
31866429
16795905
but if you swap the object as below then also same output
System.out.println(System.identityHashCode(sher1));
System.out.println(sher.hashCode());
Output is :
31866429
16795905
so why output is not reversing as i am changing the object in println method??
but when i am running below code by swapping the object in println method i am getting same result.
You shouldn't compare the results of a hashCode in one run with the results in a different run. For example, what you may have observed is that identity hash codes are allocated lazily - so whichever object you request the hash code for first gets 31866429 and the next gets 16795905 - on your particular system.
If you reverse the order within a single run you should see consistent results:
System.out.println(System.identityHashCode(sher));
System.out.println(sher1.hashCode());
System.out.println(System.identityHashCode(sher1));
System.out.println(sher.hashCode());
Here lines 1 and 4 of the output should have the same value, and lines 2 and 3 should have the same value.
It's unclear what you are trying to do. A given object reference has a given hashCode. This will be returned for both identityHashCode and a non-overridden hashCode. You however have two different object references. Therefore these will have different hashCodes if Object.hashCode is not overriden.
That you are seeing the same hashCodes between runs is chance. If you do this for long enough, and across enough JVM reboots that won't be the case.
The fact that you do see the same hashCodes in the same order is because the hashCodes are being allocated to the object reference only when you first call hashCode, not when the object is created. Therefore the first call to hashCode gets the first code in both runs, regardless of which object it is.
Try
// both lines output the same hashCode for sher
System.out.println(System.identityHashCode(sher));
System.out.println(sher.hashCode());
and
// both lines output the same hashCode for sher1
System.out.println(System.identityHashCode(sher1));
System.out.println(sher1.hashCode());
If you put all 4 lines next to each other you will see two identical lines, and then two more identical lines different to the first pair.
If you now want to return a different hashCode for hashCode() and identityHashCode then add a field and return a hashCode inside your override:
public class SherlockGCD {
private int id;
public SherlockGD(int id) { this.id = id; }
public int hashCode()
{
return id;
}
...
Here I am writing one sample code:
public class Test {
private int i;
private int j;
public Test() {
// TODO Auto-generated constructor stub
}
public Test(int i, int j)
{
this.i=i;
this.j=j;
}
}
now I am creating two objects as bellow:
Test t1= new Test(4,5);
Test t2 = new Test(4,5);
But when i am printing t1.hashcode() and t2.hashcode() they are giving different values.
But as per java's general contact they should return same value.
In fact, when i am doing same thing with String or Integer they are returning same hashcode(). Can anyone please explain why hashcode is different for t1 and t2 object?
But as per java's general contact they should return same value.
Java's equals-hashCode contract requires that if two objects are equal by Object.equals, they must have the same hashcode from Object.hashCode. But the default implementation of Object.equals is reference equality, and therefore two instances are the same if and only if they are the same instance.
Therefore, in particular, your two instances t1 and t2 are in fact not equal because you have not overridden Object.equals. They are not equal as references, and therefore not equal per Object.equals, and therefore it is acceptable for hashCode to possibly return different values. In fact, the contract explicitly says the following:
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.
Thus, we do not have a violation of the equals-hashCode contract here.
So, for your objects, if you want different instances to be equal per a logical definition of equality, you need to override Object.equals:
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
if (this == obj) {
return true;
}
if (!(obj instanceof Test)) {
return false;
}
Test other = (Test)obj;
return this.i == other.i && this.j == other.j;
}
And the equals-hashCode contract requires that you override Object.hashCode too or you'll run into some nasty bugs:
#Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + this.i;
hash = 31 * hash + this.j;
return hash;
}
What does the contract say:
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.
Let's see if we have satisfied this requirement here. If x and y are instances of Test and satisfy x.equals(y) is true, we have that x.i == y.i and x.j == y.j. Then, clearly, if we invoke x.hashCode() and y.hashCode() we have the invariant that at each line of execution in Test.hashCode we will have hash holding the same value. Clearly this is true on the first line since hash will be 17 in both cases. It will hold on the second line since this.i will return the same value whether this == x or this == y because x.i equals y.i. Finally, on the penultimate line, we will still have hash being equal across both invocations because x.j equals y.j is true as well.
Note that there is one last piece of the contract that we haven't discussed yet. This is the requirement that hashCode return a consistent value during a single execution of a Java application:
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.
The necessity of this is obvious. If you change the return value from hashCode during a single execution of the same application, you could lose your objects in hashtable-like data structures that use hashCode to keep track of objects. In particular, this is why mutating objects that are keys in hashtable-like data structures is pure evil; don't do it. I would go so far as to argue that they should be immutable objects.
In fact, when i am doing same thing with String or Integer they are returning same hashcode().
They've both overridden Object.equals and Object.hashCode.
You have not overridden the equals method in your class so the default one will be used that belongs to Object class.
Object class methods simply checks for the references whether they are referring to the same object or not.
Test t1 = new Test(4,5);
Test t2 = new Test(4,5);
are two different objects, if you don't override the equals method here, they will be equal if and only if you do
Test t2 = t1;
As you are creating two different objects here, hashcode which are NOT equal because they don't refer to the same object, hashcodes must be differnt
Remember
If two objects are equal, then their hashcode MUST be equal
But if hashcodes are equal, then its not necessary that objects should be equal
This is because of the default implementation of equals and hashCode in Java.
The JVM has no way of knowing how you decide that two objects are the same. What it does is use memory references. So, by default, the equals and hashCode methods compare memory references; i.e. two different objects are never .equals.
If you want to override this behaviour (and it is recommended you do so if you wish to use Collections for example) then all you need to do is implement your own equals and hashCode methods.
The problem is that t1 and t2 are not the same object they are different object. All objects created with new are different objects. And the default hashCode() implementation usually returns different hash codes for different objects. See Object.hashCode API.
If I override either method on a class, it must make sure that if A.equals(B) == true then A.hashCode() == B.hashCode must also be true.
Can someone show me a simple example where if this is violated, it'll cause a problem? I think it has something to do with if you use that class as the type of keys to Hashmap?
Sure:
public class Test {
private final int m, n;
public Test(int m, int n) {
this.m = m;
this.n = n;
}
public int hashCode() { return n * m; }
public boolean equals(Object ob) {
if (ob.getClass() != Test.class) return false;
Test other = (Test)ob;
return m == other.m;
}
}
with:
Set<Test> set = new HashSet<Test>();
set.put(new Test(3,4));
boolean b = set.contains(new Test(3, 10)); // false
Technically that should be true because m == 3 in both cases.
In general a HashMap works like this: it has a variable number of what are commonly called "buckets". The number of buckets can change over time (as entries are added and removed) but it is always a power of 2.
Let's say a given HashMap has 16 buckets. When you call put() to add an entry, the hashCode() of the key is calculated and then a mask is taken depending on the size of the buckets. If you (bitwise) AND the hashCode() with 15 (0x0F) you will get the last 4 bits, equaling a number between 0 and 15 inclusive:
int factor = 4;
int buckets = 1 << (factor-1) - 1; // 16
int mask = buckets - 1; // 15
int code = key.hashCode();
int dest = code & mask; // a number from 0 to 15 inclusive
Now if there is already an entry in that bucket you have what's called a collision. There are multiple ways of dealing with this but the one used by HashMap (and is probably the most common overall) is bucketing. All the entries with the same masked hashCode are put in a list of some kind.
So to find if a given key is in the map already:
Calculate the masked hash code;
Find the appropriate bucket;
If it's empty, key not found;
If is isn't empty, loop through all entries in the bucket checking equals().
Looking through a bucket is a linear (O(n)) operation but it's on a small subset. The hashcode bucket determination is essentially constant (O(1)). If buckets are sufficiently small then access to a HashMap is usually described as "near O(1)".
You can make a couple of observations about this.
Firstly, if you have a bunch of objects that all return 42 as their hash code a HashMap will still work but it will operate as an expensive list. Access will be O(n) (as everything will be in the same bucket regardless of the number of buckets). I've actually been asked this in an interview.
Secondly, returning to your original point, if two objects are equal (meaning a.equals(b) == b.equals(a) == true) but have different hash codes then the HashMap will go looking in (probably) the wrong bucket resulting in unpredictable and undefined behaviour.
This is discussed in the Item 8: Always override hashCode when you override equals of Joshua Bloch's Effective Java:
A common source of bugs is the failure to override the hashCode method. You must
override hashCode in every class that overrides equals. Failure to do so will
result in a violation of the general contract for Object.hashCode, which will pre-
vent your class from functioning properly in conjunction with all hash-based collec-
tions, including HashMap, HashSet, and Hashtable.
Here is the contract, copied from the
java.lang.Object specification:
Whenever it is invoked on the same object more than once during an execution of an 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(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.
The key provision that is violated when you fail to override hashCode is
the second one: Equal objects must have equal hash codes. Two distinct
instances may be logically equal according to the class’s equals method, but to
the Object class’s hashCode method, they’re just two objects with nothing much
in common. Therefore object’s hashCode method returns two seemingly random
numbers instead of two equal numbers as required by the contract.
For example, consider the following simplistic PhoneNumber class, whose
equals method is constructed according to the recipe in Item 7:
public final class PhoneNumber {
private final short areaCode;
private final short exchange;
private final short extension;
public PhoneNumber(int areaCode, int exchange,
int extension) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(exchange, 999, "exchange");
rangeCheck(extension, 9999, "extension");
this.areaCode = (short) areaCode;
this.exchange = (short) exchange;
this.extension = (short) extension;
}
private static void rangeCheck(int arg, int max,
String name) {
if (arg < 0 || arg > max)
throw new IllegalArgumentException(name +": " + arg);
}
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.extension == extension &&
pn.exchange == exchange &&
pn.areaCode == areaCode;
}
// No hashCode method!
... // Remainder omitted
}
Suppose you attempt to use this class
with a HashMap:
Map m = new HashMap();
m.put(new PhoneNumber(408, 867, 5309), "Jenny");
At this point, you might expect
m.get(new PhoneNumber(408 , 867,
5309)) to return "Jenny", but it
returns null. Notice that two PhoneNumber instances are
involved: One is used for insertion
into the HashMap, and a second, equal,
instance is used for (attempted)
retrieval. The PhoneNumber class’s
failure to override hashCode causes
the two equal instances to have
unequal hash codes, in violation of
the hashCode contract. Therefore the
get method looks for the phone number
in a different hash bucket from the
one in which it was stored by the put
method. Fixing this problem is as
simple as providing a proper hashCode
method for the PhoneNumber class.
[...]
See the Chapter 3 for the full content.
Containers like HashSet rely on the hash function to determine where to put it, and where to get it from when asked for it. If A.equals(B), then a HashSet is expecting A to be in the same place as B. If you put A in with value V, and look up B, you should expect to get V back (since you've said A.equals(B)). But if A.hashcode() != B.hashcode(), then the hashset may not find where you put it.
Here's a little example:
Set<Foo> myFoos = new HashSet<Foo>();
Foo firstFoo = new Foo(123,"Alpha");
myFoos.add(firstFoo);
// later in the processing you get another Foo from somewhere
Foo someFoo = //use imagination here...;
// maybe you get it from a database... and it's equal to Foo(123,"Alpha)
if (myFoos.contains(someFoo)) {
// maybe you win a million bucks.
}
So, imagine that the hashCode that gets created for firstFoo is 99999 and it winds up at a specific spot in the myFoos HashSet. Later when you get the someFoo and you look for it in the myFoos HashSet, it needs to generate the same hashCode so you can find it.
It's exactly because of hash tables.
Because of the possibility of hash code collisions, hash tables need to check identity as well, otherwise the table can't determine if it found the object it was looking for, or one with the same hash code. So every get() in a hash table calls key.equals(potentialMatch) before returning a value.
If equals() and hashCode() are inconsistent you can get very inconsistent behavior. Say for two objects, a and b, a.equals(b) returns true, but a.hashCode() != b.hashCode(). Insert a and a HashSet will return false for .contains(b), but a List created from that set will return true (because the list doesn't use hash codes).
HashSet set = new HashSet();
set.add(a);
set.contains(b); // false
new ArrayList(set).contains(b); // true
Obviously, that could be bad.
The idea behind this is that two objects are "equal" if all of their fields have equal values. If all of fields have equal values, the two objects should have the same hash value.