简体   繁体   English

如何实例泛型参数化类

[英]How to instance generic parameterized class

I just implement a MapBuilder to build map easy, But when i try to get an instance of HashMap.class,I suddenly found that I can't use HashMap.class to get such an instance. 我只是实现了MapBuilder来轻松构建地图,但是当我尝试获取HashMap.class的实例时,我突然发现我不能使用HashMap.class来获取这样的实例。

It's illegal! 这是非法的!

So can anybody tell me why and how to solve this problem? 所以有人能告诉我为什么以及如何解决这个问题?

The MapBuilder is follow: 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;
        }
    }
}

And the test code is below: 测试代码如下:

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

It's impossible to obtain a parameterized class type variable for a generic type, as Reimeus has said. 正如Reimeus所说,获取泛型类型的参数化类类型变量是不可能的。 So you have three choices. 所以你有三个选择。

First, you can live with the unchecked cast: 首先,您可以使用未经检查的演员:

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

Second, you can reify the parameters for a class by extending it (in this example, using an anonymous inner class): 其次,可以通过(在该示例中使用匿名内部类)延伸它具体化的一类的参数:

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

Or third, and best, just take the Map instance instead of a class in start() . 或者第三,也是最好的,只需使用Map实例而不是start()中的类。 You're not saving the user any work by taking the Class rather than an instance of Map , and the first thing you do is create an instance of it. 您不是通过使用Class而不是Map的实例来保存用户的任何工作,而您要做的第一件事就是创建它的实例。

By passing it in, the user can even tweak the settings of the map (eg for a HashMap , set the load factor, for TreeMap , specify the Comparator ) so it's a better alternative anyway. 通过传入,用户甚至可以调整地图的设置(例如,对于HashMap ,为TreeMap设置加载因子,指定Comparator ),因此无论如何它都是更好的选择。 If you need to, you can assert that it's empty when it's passed in. 如果需要,可以断言传入时它是空的。

If for some reason you really need a factory, don't use Class : it doesn't work well as a factory, because the only way you can customize the instance that Class creates is by subclassing the class and providing a new no-arg constructor. 如果由于某种原因你真的需要一个工厂,不要使用Class :它不能很好地作为工厂,因为你可以自定义Class创建的实例的唯一方法是通过继承类并提供一个新的no-arg构造函数。 Just create an interface Factory<T> that has a method T create() and then accept a Factory<? extends Map<K, V> 只需创建一个具有T create()方法的接口Factory<T>然后接受一个Factory<? extends Map<K, V> Factory<? extends Map<K, V> . Factory<? extends Map<K, V>

First since start takes a class you would have to pass it an unparameterized class such as HashMap.class . 首先,因为start接受一个类你必须通过它的unparameterized类如HashMap.class Second, as you're returning a generic type Map , you would have to make your local type match also, so to use: 其次,当您返回泛型类型Map ,您还必须使本地类型匹配,因此要使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM