I am reading Effective Java - Item 29. It talks about Heterogeneous container, in the example:
private Map, Objec
First, note that Item 29 is really about the general concept of using parameterized keys:
Sometimes, however, you need more flexibility. For example, a database row can have arbitrarily many columns, and it would be nice to be able to access all of them in a typesafe manner. Luckily there is an easy way to achieve this effect. The idea is to parameterize the key instead of the container.
The intent of this item is to demonstrate that you can use generics in more ways than just by parameterizing a type. The Heterogeneous Container pattern is simply an example of this technique. Admittedly, the item could make that point clearer with a better title like "Consider using parameterized methods to enforce type safety when working with arbitrary numbers of types".
The Heterogeneous Container pattern the item demonstrates is specifically for the case where you want to associate certain types with a particular instance of each type. Guava includes an implementation of this pattern with their ClassToInstanceMap type (more details). They also provide the more powerful TypeToInstanceMap that supports arbitrary generic types (e.g. List<String>
) with an admittedly slightly more cumbersome API.
All of this is to say that there's nothing stopping you from creating a similarly structured class that supports multiple instances of a given type. We could easily take the ClassToInstanceMap
API and create a ClassToInstanceMultimap
type (extending Guava's Multimap API):
public interface ClassToInstanceMultimap<B> extends Multimap<Class<? extends B>, B> {
/**
* Returns the values the specified class is mapped to, or an empty collection if no
* entries for this class is present. This will only return a value that was
* bound to this specific class, not a value that may have been bound to a
* subtype.
*/
<T extends B> Collection<T> getInstances(Class<T> type);
/**
* Stores an entry mapping the specified class to the specified value. Does <i>not</i>
* associate this value with any of the class's supertypes.
*
* @return {@code true} if the method increased the size of the multimap, or
* {@code false} if the multimap already contained the key-value pair and doesn't allow
* duplicates
*/
<T extends B> T putInstance(Class<T> type, T value);
}
Guava doesn't currently include such an interface, but the implementation of ClassToInstanceMap is pretty straightforward, so you could easily create your own ClassToInstanceMultimap
implementations.
If you put two strings the second will override the first one. So it is useful only if this behaviour is desired. If you want to store more objects under the same key you can use other containers, for example :
Map<Class<?>, List<Object>>
Or you can use MultiMap from Guava : http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Multimap.html
Or you can use MultiMap from apache commons : http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/MultiMap.html