Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Java HashMap and IdentityHashMap?

Tags:

java

I am using HashMap.

Below is example code.

Classes MyKey and MyValue are inhereted from Object in simple way.

Java documentation says for Object and methods hashCode() and equals():

"As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)"

"The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). "

My question is:

Can I trust that HashMap works in my example? If not what would be right way to put simple objects into map without rewriting methods hashCode() and equals()?

I am not sure but I have heard that Java may change location and addresss of user objects during execution of program (Was it GC which may do that?)

If address and hash code of key2 have changed before the line

    MyValue v = m.get(key2);

then calling m.get(key2) would return wrong value, null?

If this is true then I believe that also IdentityHashMap() is useless for same reasons.

class MyKey
{
  Integer v;
  //<Perhaps more fields>
  MyKey(Integer v) {this.v=v;}
}

class MyValue
{
  String s;
  //<Perhaps more fields>
  MyValue(String s) {this.s = s;}
}


Then some code:

Map<MyKey,MyValue> m = new HashMap<MyKey,MyValue>();

MyKey key1 = new MyKey(5);
MyKey key2 = new MyKey(6);
MyKey key3 = new MyKey(7);


m.put(key1, new MyValue("AAA"));
m.put(key2, new MyValue("BBB"));
m.put(key3, new MyValue("CCC"));

.
.

//Is it sure that I will get value "AAA" here
//if entry with key2 has not been removed from map m?
MyValue v = m.get(key2);
System.out.println("s="+v.s);
like image 748
heivik Avatar asked Dec 01 '25 15:12

heivik


2 Answers

Can I trust that HashMap works in my example? If not what would be right way to put simple objects into map without rewriting methods hashCode() and equals()?

You cannot avoid providing a sensible hashCode and equals methods, it is required for HashMap and other Hash collections to work. (with the exception of IdentityHashMap)

I am not sure but I have heard that Java may change location and addresss of user objects during execution of program (Was it GC which may do that?)

While this is true, it has nothing to do with your main question.

If address and hash code of key2 have changed before the line

The address and hashCode have nothing to do with one another. If the address changes it doesn't change the hashCode and if you change the hashCode it doesn't change the address.

If this is true then I believe that also IdentityHashMap() is useless for same reasons.

Even if you assume hashCode is useless, this doesn't affect IndentityHashCode because it doesn't use the hashCode or equals methods.


Objects are basically allocated continuously in memory from the Eden space. If you run

Object[] objects = new Object[20];
for (int i = 0; i < objects.length; i++)
    objects[i] = new Object();

Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
for (int i = 0; i < objects.length; i++) {
    int location = unsafe.getInt(objects, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * i);
    System.out.println(Integer.toHexString(location) + ": hashCode=" + Integer.toHexString(objects[i].hashCode()));
}

you might expect them to be continuous if the followed some memory location but they don't

eac89d10: hashCode=634e3372
eac89d20: hashCode=2313b44d
eac89d30: hashCode=62a23d38
eac89d40: hashCode=9615a1f
eac89d50: hashCode=233aa44
eac89d60: hashCode=59243f75
eac89d70: hashCode=5ac2480b
eac89d80: hashCode=907f8ba
eac89d90: hashCode=6a5a7ff7
eac89da0: hashCode=5b8767ad
eac89db0: hashCode=50ba0dfc
eac89dc0: hashCode=2198a037
eac89dd0: hashCode=2b3e8c1c
eac89de0: hashCode=17609872
eac89df0: hashCode=46b8705b
eac89e00: hashCode=76d88aa2
eac89e10: hashCode=275cea3
eac89e20: hashCode=4513098
eac89e30: hashCode=6e4d4d5e
eac89e40: hashCode=15128ee5

Java has four different way of encoding references in 32-bit and 64-bit, however if your maximum heap size is less than 2 GB it will be a simple 32-bit address as it was when I ran this example.

like image 59
Peter Lawrey Avatar answered Dec 04 '25 07:12

Peter Lawrey


Can I trust that HashMap works in my example? If not what would be right way to put simple objects into map without rewriting methods hashCode() and equals()?

Your example does not provide hashCode or equals, so it will use the defaults. The dafaults work with the object identity, which means o.equals(o2) will be true only if o and o2 refer to the same object.

 MyKey m = new MyKey(1);
 MyKey m2 = new MyKey(1);
 MyKey m3 = m;

 map.put(m,...);
 map.get(m);//works
 map.get(m2); //different object
 map.get(m3);//works same object

I am not sure but I have heard that Java may change location and addresss of user objects during execution of program (Was it GC which may do that?)

The address of an object is not relevant, while the default hashCode might use it this happens only once for each object and then stays the same.

like image 36
josefx Avatar answered Dec 04 '25 06:12

josefx



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!