如何实例泛型参数化类

时间:2012-10-28 15:07:13

标签: java generics

我只是实现MapBuilder来轻松构建地图, 但是当我尝试获取HashMap.class的实例时,我突然发现我无法使用HashMap.class来获取这样的实例。

这是非法的!

那么有人可以告诉我为什么以及如何解决这个问题?

MapBuilder如下:

import java.util.Map;

public abstract class MapBuilder {

    public static <K, V, T extends Map<K, V>> InnerMapBuilder<T, K, V> start(
            Class<T> clazz) {
        return new InnerMapBuilder<>(clazz);
    }

    public static class InnerMapBuilder<T extends Map<K, V>, K, V> {

        private T target;

        public InnerMapBuilder(Class<T> clazz) {
            try {
                target = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }

        public InnerMapBuilder<T, K, V> put(K key, V val) {
            target.put(key, val);
            return this;
        }

        public T get() {
            return target;
        }
    }
}

测试代码如下:

public static void main(String[] args) {
    HashMap<String, String> v = start(HashMap<String,String>.class).put("a", "b").get();
    System.out.println(v);
}

2 个答案:

答案 0 :(得分:1)

正如Reimeus所说,获取泛型类型的参数化类类型变量是不可能的。所以你有三个选择。

首先,您可以使用未选中的演员:

Class<? extends Map<String, Integer>> clazz = 
    (Class<? extends Map<String, Integer>>) HashMap.class;

其次,您可以通过扩展它来 reify 类的参数(在本例中,使用匿名内部类):

Class<? extends Map<String, Integer>> clazz =
     new HashMap<String, Integer>() {}.getClass();

或者第三,也是最好的,只需使用Map实例而不是start()中的类。您不是通过Class而不是Map的实例来保存用户的任何工作,而您要做的第一件事就是创建它的实例。

通过传入,用户甚至可以调整地图的设置(例如,对于HashMap,为TreeMap设置加载因子,指定Comparator),这样就可以了无论如何,更好的选择。如果需要,可以断言它在传入时为空。

如果由于某种原因你确实需要工厂,请不要使用Class:它不能用作工厂,因为你可以自定义Class创建的实例的唯一方法是通过继承类并提供一个新的无参数构造函数。只需创建一个具有方法Factory<T>的接口T create(),然后接受Factory<? extends Map<K, V>

答案 1 :(得分:0)

首先,因为start需要一个类,所以你必须向它传递一个未参数化的类,例如HashMap.class。其次,当您返回泛型类型Map时,您还必须使本地类型匹配,以便使用:

Map<String, String> v = start(HashMap.class).put("a", "b").get();