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());
}
- 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.
// 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