Header Ads

Java- Generics : Creating a typesafe heterogeneous container

The most common use of generics is for collections, such as Set and Map, and single-element containers. In all of these uses, it is the container that is parameterized. This limits you to a fixed number of type parameters per container. Normally that is exactly what you want. A Set has a single type parameter, representing its element type; a Map has two, representing its key and value types; and so forth.
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.
So , the question is how can we do it.The idea is to parameterize the key instead of the container. Then present the parameterized key to the container to insert or retrieve a value. The generic type system is used to guarantee that the type of the value agrees with its key.
For example, suppose we have a use case where we need to store favorites in a data structure and all favorites can be of different types.Consider a Favorites class that allows its clients to store and retrieve a “favorite” instance of arbitrarily many other classes. The Class object will play the part of the parameterized key. Here is how the API for favorite class should look like.
// Typesafe heterogeneous container  - API
public class Favs {
public <T>  void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}

 
// Typesafe heterogeneous container  - client
public static void main(String[] args) {
Favs f = new Favs();
f.putFav(String.class, "Java");
f.putFav(Integer.class, 0xcafebabe);
f.putFav(Class.class, Favs.class); 

String favString = f.getFav(String.class);
int favoriteInteger = f.getFav(Integer.class);
Class<?> favoriteClass = f.getFav(Class.class);
System.out.printf("%s %x %s%n", favString,
favoriteInteger, favoriteClass.getName());
}

Here first parameter of putFav() method takes class type and second takes the corresponding instance.
  • A Favs instance is typesafe: it will never return an Integer when you ask it for a String. 
  • It is also heterogeneous: unlike an ordinary map, all the keys are of different types. 
Therefore, we call Favorites a typesafe heterogeneous container. Implementation of Favs class can be done as follows which is fairly simple:

// Typesafe heterogeneous container - implementation
public class Favs {
private Map<Class<?>,Object> favorites =new HashMap<Class<?>,Object>();
public <T>  void putFavorite(Class<T> type, T instance) {
if (type == null)
throw new NullPointerException("Type is null");
favorites.put(type, instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}

Here each Favs instance is backed by a private Map<Class<?>,Object> called favorites.This means that every key can have a different parameterized type: one can be Class, the next Class, and so on. That’s where the heterogeneity comes from. 

No comments

Powered by Blogger.