我怎样才能在Java中实例化一个泛型类型? [英] How can I instantiate a generic type in 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
}
}
}
$ p $然而,看到实现这个目标有多麻烦,包括使用反射的性能成本,首先需要研究其他方法。
如果您绝对需要采用此路线,并且 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);
}
}
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 Constructor
s, 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屋!