如何在Java中实例化泛型类型?

Ben*_*ank 12 java generics

我已经在我的应用程序中添加了一个人类可读的配置文件,java.util.Properties并尝试在其周围添加包装以使类型转换更容易.具体来说,我希望返回的值从提供的默认值"继承"它的类型.这是我到目前为止所得到的:

protected <T> T getProperty(String key, T fallback) {
    String value = properties.getProperty(key);

    if (value == null) {
        return fallback;
    } else {
        return new T(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

(完整示例源.)

getProperty("foo", true)无论是从属性文件中读取还是类似于字符串,整数,双精度和c,返回值都将是一个布尔值.当然,上面的代码段实际上并没有编译:

PropertiesExample.java:35: unexpected type
found   : type parameter T
required: class
                        return new T(value);
                                   ^
1 error
Run Code Online (Sandbox Code Playgroud)

我做错了,还是我只是想做一些无法做到的事情?

编辑:用法示例:

// I'm trying to simplify this...
protected void func1() {
    foobar = new Integer(properties.getProperty("foobar", "210"));
    foobaz = new Boolean(properties.getProperty("foobaz", "true"));
}

// ...into this...
protected void func2() {
    foobar = getProperty("foobar", 210);
    foobaz = getProperty("foobaz", true);
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*ora 13

由于类型擦除,您无法实例化通用对象.通常,您可以保留对Class表示该类型的对象的引用并使用它来调用newInstance().但是,这仅适用于默认构造函数.由于您要使用带参数的构造函数,因此您需要查找该Constructor对象并将其用于实例化:

protected <T> T getProperty(String key, T fallback, Class<T> clazz) {
    String value = properties.getProperty(key);

    if (value == null) {
        return fallback;
    } else {

        //try getting Constructor
        Constructor<T> constructor;
        try {
            constructor = clazz.getConstructor(new Class<?>[] { String.class });
        }
        catch (NoSuchMethodException nsme) {
            //handle constructor not being found
        }

        //try instantiating and returning
        try {
            return constructor.newInstance(value);
        }
        catch (InstantiationException ie) {
            //handle InstantiationException
        }
        catch (IllegalAccessException iae) {
            //handle IllegalAccessException
        }
        catch (InvocationTargetException ite) {
            //handle InvocationTargetException
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,看到实现这一目标有多麻烦,包括使用反射的性能成本,首先要考虑其他方法.

如果你绝对需要走这条路,如果T仅限于一组不同的在编译时已知的类型,一个折衷办法是保持静态MapConstructors,这是在启动时加载-这样你就不必动态每次调用此方法时都要查看它们.例如a Map<String, Constructor<?>>Map<Class<?>, Constructor<?>>,使用静态块填充.