Is it possible to declare a Map that maps from keys of a specific subclass to values of a specific subclass but ensuring that both classes share the same Type parameter?
For the background:
both ClassA and ClassB implement behaviour for a common resource
public abstract class ClassA<T> {
public abstract T getResource() ;
}
public abstract class classB<T> {
public abstract void consoumeResource(T resource);
}
i want to map from implementations of ClassA and ClassB and ensure only "compatible" pairs can be put together in one entry.
extends Number> represents a list of Number or its sub-types such as Integer and Double. Lower Bounded Wildcards: List<? super Integer> represents a list of Integer or its super-types Number and Object.
super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T .
Suppose if the key is of type String and the corresponding value is of type Integer, then we can initialize it as, Map< String , Integer > map = new HashMap< String ,Integer >(); The map can now only accept String instances as key and Integer instances as values.
super is a lower bound, and extends is an upper bound.
Another way would be to provide your own Map
implementation. There's not much code needed if you extend an existing implementation, and use your new type:
public class CompatibleHashMap<T> extends HashMap<ClassA<T>, ClassB<T>> {
}
Now, a CompatibleHashMap<String>
only lets you put ClassA<String>
as keys and ClassB<String>
as values.
EDIT:
As you mentioned in your comment, this way you are tying yourself to a Map
implementation. You can overcome this by doing something like the following:
public class CompatibleMap<T> implements Map<ClassA<T>, ClassB<T>> {
private Map<ClassA<T>, ClassB<T>> map;
public CompatibleMap(Map<ClassA<T>, ClassB<T>> map) {
this.map = map;
}
@Override
public Set<List<T>> keySet() {
return map.keySet();
}
// ... implement all other Map methods by calling the method on map.
}
You can then instantiate it like
CompatibleMap<String> map = new CompatibleMap<>(new HashMap<ClassA<String>, ClassB<String>>());
This way, you are not tied to a specific Map
implementation, and the compiler will throw an error if the generic types of the map
, ClassA
and ClassB
are not the same.
You can't do this in the Map declaration but you can do this using methods which access/update the map.
e.g.
private final Map<Class, Builder> builderMap = new LinkedHashMap<>();
public <T> void addBuilder(Class<T> tClass, Builder<T> tBuilder) {
builderMap.put(tClass, tBuilder);
}
public <T> Builder<T> getBuilderFor(Class<T> tClass) {
@SuppressWarnings("unchecked")
Builder<T> tBuilder = (Builder<T>) builderMap.get(tClass);
return tBuilder;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With