How to check if Object is instanceof HashMap<?,?>[] in Java?

I have in java an array of HashMaps

HashMap<String, String>[] convertTags = new HashMap[1];
HashMap<String, String> tag = new HashMap<>();
tag.put("key", "test-tag");
tag.put("value", "test-value");
convertTags[0] = tag;

And in another class, I pass this convertTags object to a function that takes in a generic Object. Based on the type of object, I want to run different code. However, when I have an if statement to check the instanceof the array of HashMaps, it doesn't seem to recognize my convertTags object.

public static void function (Object obj) {
...
   if (obj instanceof HashMap<?, ?>[]) {
      //do stuff
   }
}

Am I missing something? Calling .getClass() on convertTags object returns class [Ljava.util.HashMap;


Solution 1:

When doing type checks with instanceof, you cannot use a generic type as the check: you must use a raw type. The reason for this is simple: most of the generic type information is erased at compile-time and no longer exists at run-time. To the JVM at run-time, these types are the same: List<T>, List<String>, List<Hashmap<E>>, and List. If Java allowed the use of generic types for instanceof operations, serious type errors could result.

In fact, it is not strictly correct to allow operations like:

if (obj instanceof Hashmap<?,?>[]) { ...

The compiler allows this because unbounded wildcard types are the only type of reified generics that exist in Java. Many authors discourage the use of unbounded wildcards in this situation because they may imply that the use of other (non-reifiable) generic types is valid. Rather, this is the uncommon situation where it is best to use the raw type:

if (obj instanceof Hashmap[]) { ...
    Hashmap<?,?>[] map = (Hashmap<?,?>[]) obj
        :
        :

Because the type has been checked, the cast is legal and no compiler warning will be emitted by the above snippet.

If run-time information is needed about the types in the Hashmap, you can consider two approaches (that can be mixed):

  • generifying function() to take type parameters for the keys and/or values
  • passing Class<T> objects as run-time type tokens for the types of the keys and values.