Heterogeneous Container Iteration

I use a heterogeneous container like this one . I can easily add and remove objects from the container:

Favorites f = new Favorites(); f.putFavorite(String.class, "Java"); String someString = f.getFavorite(String.class); 

But there seems to be no easy way to iterate over such a container. I can add the keySet() method to the Favorites class and simply return the key set of the internal Map object:

 public Set<Class<?>> keySet() { return favorites.keySet(); } 

Now I would like to iterate over the keys, use the keys to get the associated values, and call some methods on the received objects:

 for (Class<?> klass : f.keySet()) { // f.getFavorite(klass).<SOME_METHOD_SPECIFIC_TO_THE_CLASS-KEY> } 

I thought I could access the methods of the objects stored in my container by calling klass.cast(f.getFavorite(klass)).SOME_METHOD() , but it doesn’t work either (which means I cannot access which any methods other than Object methods).

Let's say that in my use case, I would like to check the interfaces of all these objects, which I iterate over and act according to the detected interface. Suppose also that I can have dozens of objects of different classes, and they all implement one of three interfaces.

The only solution I can think of is to isinstance my code with dozens of isinstance checks, but I would prefer a less cumbersome approach (for example, checking if a given object implements one of the three interfaces).

+6
source share
2 answers

When trying to call a specific method for each record, you basically say that you know better than the compiler, and you know that each record has a specific superclass.

If you know what this case is, you can use Class#asSubclass to enter klass as Class<? extends KnownSuper> Class<? extends KnownSuper> so getFavorite then returns a subclass of KnownSuper (and therefore exposed the method):

 Class<KnownSuper> superClass = KnownSuper.class; //class with callMethod() for (Class<?> klass : f.keySet()) { f.getFavorite(klass.asSubClass(superClass)).callMethod() } 

However, this will obviously throw a runtime exception if one of the key classes does not extend KnownSuper . Therefore, if it would be safe above, you should parameterize your heterogeneous container to accept only key classes that extend from KnownSuper in the first place.

If not all entries are of this type, you can also first check if the key is suitable for iteration:

 Class<KnownSuper> superClass = KnownSuper.class; //class with callMethod() for (Class<?> klass : f.keySet()) { if (superClass.isAssignableFrom(klass)) { f.getFavorite(klass.asSubClass(superClass)).callMethod() } } 
+5
source

Just go through this simple example.

Say you have a favorite class definition

 public class Favorites extends HashMap<String, String> { } 

Here is a test class

 public class TestGeneric { public static void main(String[] args) { Favorites f = new Favorites(); f.put("test", "test"); for (String test1 : f.keySet()) { f.get("").charAt(index)// you will see all string specific method as compiler knows in advance what object map going to contain } } 

The moment you change Favorites extends HashMap<String, String> to Favorites extends HashMap , you will simply expose yourself to specific methods, since the compiler does not know in advance which Favorites will be placed on the map.

0
source

All Articles