Reputation: 187399
I'm trying to write a Map
builder. One of the constructors will allow the client to specify the type of Map
they wish to build
public class MapBuilder<K, V> {
private Map<K, V> map;
/**
* Create a Map builder
* @param mapType the type of Map to build. This type must support a default constructor
* @throws Exception
*/
public MapBuilder(Class<? extends Map<K, V>> mapType) throws Exception {
map = mapType.newInstance();
}
// remaining implementation omitted
}
The intent is that it should be possible to construct instances of the builder with:
MapBuilder<Integer, String> builder = new MapBuilder<Integer, String>(LinkedHashMap.class);
or
MapBuilder<Integer, String> builder = new MapBuilder<Integer, String>(HashMap.class);
It seems that the type signature of the constructor argument doesn't currently support this, because the line above causes a "Cannot resolve constructor" compilation error.
How can I change my constructor so that it accepts classes that implement Map
only?
Upvotes: 8
Views: 407
Reputation: 44250
The problem is that LinkedHashMap.class
is
Class<LinkedHashMap>
and not something like
Class<LinkedHashMap<Integer, String>>
These are also inconvertible types (so you can't cast it) and there's no way to get an instance of the latter.
What you can do is change the constructor to
public MapBuilder(Class<? extends Map> mapType) throws Exception
Generics are erased at run-time so at run-time all Map
s will behave just like Map<Object, Object>
anyway. Therefore it doesn't matter that the class you're constructing from is using the raw type.
By the way, Class::newInstance
is deprecated. Use
mapType.getConstructor().newInstance()
Upvotes: 2
Reputation: 19910
Use a Supplier
instead of a Class
:
public MapBuilder(Supplier<? extends Map<K, V>> supplier) {
map = supplier.get();
}
Which then can be called like this:
MapBuilder<Integer, Integer> builder = new MapBuilder<>(LinkedHashMap::new);
This is also safer, because a Class<Map>
could have no default constructor, which would throw an error (which is not very responsive code)
Upvotes: 10
Reputation: 394146
The following will work:
public MapBuilder(Class<? extends Map> mapType) throws Exception {
map = mapType.newInstance();
}
Upvotes: 2