Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using the Class instance as a Map key a best practice?

Tags:

java

I have read somewhere that using the class instances as below is not a good idea as it might cause memory leaks. Can someone tell me if that is a valid statement? Or are there any problems using them this way?

Map<Class<?>,String> classToInstance = new HashMap();  classToInstance.put(String.class,"Test obj"); 
like image 429
Aravind Yarram Avatar asked Apr 12 '10 21:04

Aravind Yarram


People also ask

Can you use any class as a Map key?

Yes, we can use any object as key in a Map in java but we need to override the equals() and hashCode() methods of that object class.

What should you do when using a custom Java object as a key in a Map?

Therefore, to use an object as a key in HashMap , HashSet , or Hashtable in Java, we need to override equals and hashcode methods of that object since default implementation of these methods simply check for the instance equality.

What should be done if we need the HashMap Key to be of any user defined type?

If you want to make a mutable object as a key in the hashmap, then you have to make sure that the state change for the key object does not change the hashcode of the object. This can be done by overriding the hashCode() method. But, you must make sure you are honoring the contract with equals() also.

Do keys in a Map need to be unique?

HashMap is a collection to store (key,value) pairs and According to the documentation of HashMap the keys are always unique. If you add a key which already exists(collision) in the hashmap, the old value will be replaced.


2 Answers

Yes, you do need to be cautious! For example, if your code is running in a web container and you are in the habit of doing hot deployment of webapps, a retained reference to a single class object can cause a significant permgen memory leak.

This article explains the problem in detail. But in a nutshell, the problem is that each class contains a reference to its classloader, and each classloader contains references to every class that it has loaded. So if one class is reachable, all of them are.

The other thing to note is that if one of the classes that you are using as a key is reloaded then:

  1. The old and new versions of the class will not be equal.
  2. Looking up the new class will initially give a "miss".
  3. After you have added the new class to the map, you will now have two different map entries for the different versions of the class.
  4. This applies even if there is no code difference between the two versions of the class. They will be different simply because they were loaded by different classloaders.

From Java 8 - Permgen was removed. Do you think it is ok to use Class instance as HashMap key in any situations?

Be aware that you will still have a memory leak. Any dynamicly loaded class used in your HashMap (key or value) and (at least) other dynamically loaded classes will be kept reachable. This means the GC won't be able to unload / delete them.

What was previously a permgen leak is now a ordinary heap and metaspace storage leak. (Metaspace is where the class descriptors and code objects for the classes are kept.)

like image 148
Stephen C Avatar answered Oct 02 '22 19:10

Stephen C


No, that's not a problem. As long as you were creating an instance of the class anyway, you're not using any more memory by holding a reference to the class itself.

like image 36
Michael Myers Avatar answered Oct 02 '22 20:10

Michael Myers