我怎样才能在Java中实例化一个泛型类型? [英] How can I instantiate a generic type in Java?

查看:673
本文介绍了我怎样才能在Java中实例化一个泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用 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);
}
}

(完整的示例源代码)



getProperty(foo,true) code>将会是一个布尔值,无论它是从属性文件中读取,还是类似的字符串,整数,双精度和& c。当然,上面的代码片段并不实际编译:

  PropertiesExample.java:35:unexpected输入
found:输入参数T
required:class
return new T(value);
^
1错误

我做错了,还是我简单试图做一些无法完成的事情?



编辑:使用示例:

//我试图简化这个...
protected void func1(){
foobar = new Integer( properties.getProperty(foobar,210));
foobaz = new Boolean(properties.getProperty(foobaz,true));
}

// ...进入此...
保护无效func2(){
foobar = getProperty(foobar,210);
foobaz = getProperty(foobaz,true);


解决方案

由于类型擦除,你不能实例化通用对象。通常情况下,您可以保留对 Class 代表该类型的对象的引用,并使用它来调用 的newInstance() 。但是,这只适用于默认构造函数。既然你想使用带参数的构造函数,你需要查看 构造函数 对象并将其用于实例化:

 受保护的< T> T getProperty(String key,T fallback,Class< T> clazz){
String value = properties.getProperty(key);

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

//尝试获取构造函数
构造函数< T>构造函数;
try {
constructor = clazz.getConstructor(new Class<?> [] {String.class});

catch(NoSuchMethodException nsme){
//处理构造函数未被找到
}

//尝试实例化并返回
尝试{
return constructor.newInstance(value);

catch(InstantiationException ie){
//处理InstantiationException异常
}
catch(IllegalAccessException iae){
//处理IllegalAccessException
}
catch(InvocationTargetException ite){
//处理InvocationTargetException
}
}
}


如果您绝对需要采用此路线,并且 T 仅限于已知的一组不同的类型编译时,妥协方法是保持构造函数的一个静态 Map ,这是在启动时加载的 - 这样您无需在每次调用此方法时动态查找它们。例如,一个 Map >< / code>或 Map< Class<> ;,构造函数<> / code>,它使用静态块填充。


I've added a human-readable configuration file to my app using java.util.Properties and am trying to add a wrapper around it to make type conversions easier. Specifically, I want the returned value to "inherit" it's type from the provided default value. Here's what I've got so far:

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

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

(Full example source.)

The return value from getProperty("foo", true) would then be a boolean regardless of whether it was read from the properties file and similarly for strings, integers, doubles, &c. Of course, the above snippet doesn't actually compile:

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

Am I doing this wrong, or am I simply trying to do something which can't be done?

Edit: Usage example:

// 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);
}

解决方案

Due to type erasure, you can't instantiate generic objects. Normally you could keep a reference to the Class object representing that type and use it to call newInstance(). However, this only works for the default constructor. Since you want to use a constructor with parameters, you'll need to look up the Constructor object and use it for the instantiation:

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
        }
    }
}

However, seeing how much trouble it is to achieve this, including the performance cost of using reflection, it's worth looking into other approaches first.

If you absolutely need to take this route, and if T is limited to a distinct set of types known at compile time, a compromise would be to keep a static Map of Constructors, which is loaded at startup - that way you don't have to dynamically look them up at every call to this method. For example a Map<String, Constructor<?>> or Map<Class<?>, Constructor<?>>, which is populated using a static block.

这篇关于我怎样才能在Java中实例化一个泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆