Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restrict a generic Class parameter to classes that implement Map

Tags:

java

generics

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?

like image 513
Dónal Avatar asked Feb 18 '19 10:02

Dónal


People also ask

How do I restrict a generic type in Java?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class.

When it is required to restrict the kinds of types that are allowed to be passed to a type parameter are used?

Bounded Type Parameters There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

Can a generic class definition can only have one type parameter?

A class definition can have more than one type parameter.


2 Answers

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)

like image 187
Lino Avatar answered Oct 22 '22 05:10

Lino


The following will work:

public MapBuilder(Class<? extends Map> mapType) throws Exception {
    map = mapType.newInstance();
}
like image 29
Eran Avatar answered Oct 22 '22 03:10

Eran