在处理配置管理器对象时,我想实现一个方法,该方法将从管理器的内部索引中检索一个值并将其自动转换为所需的类型,从而无需显式转换。我认为这很容易,使用Java在方法头中提供的泛型系统。所以,我构建了我的方法:
public <T> T getSettingAutocast(String key)
{
T retV = null;
try {retV = (T) getSetting(key);}catch (ClassCastException ignored){}
return retV;
}
我通过使用它来从设置注册表中提取文件来测试该方法,如下所示:
File f = configIO.getSettingAutocast("file");
注册表已经预先加载了该密钥地址的File对象。
这按预期工作。但是,如果我将File
替换为Integer
,事情就不会那么顺利 - 我得到了ClassCastException
。在调试模式下查看它,T
是方法开头的正确类型,但是当调用强制转换时,它只会变换为getSetting
返回的任何类型。
我的印象是编译器试图从目标对象推断<T>
(在本例中为File
或Integer
),而不是方法体中的任何类型本身。如果有人能够提供更多关于编译器在方法方面如何处理类型推断的见解,那将非常感激。
答案 0 :(得分:2)
您仍然传播ClassCastException
的原因是此方法实际上 。
在类型擦除之后,分配是:
retV = (Object) getSetting(key);
当然,这是成功的,因为一切都是一个对象(除非它是原始的,但是你不能在这里使用泛型)。
演员阵容实际上是对通话网站的抨击:
Integer = (Integer) configIO.getSettingAutocast("file");
(尝试反编译代码,你会在那里看到checkcast
指令。)
所以 是抛出异常的地方,你应该从堆栈跟踪中注意到。
我的印象是......
不。通过使用此模式,您可以得到您应得的。强制转换是告诉编译器信任你的一种方式,因为你知道它没有的某些类型信息;在这种情况下,你只是猜测类型,并弄错了。
返回对象,并检查呼叫站点的类型。是的,它会变得更加丑陋;但丑陋的代码比漂亮但破坏的代码更好。你投射的这个事实应该让你停下来思考可能在这里出错了什么,而不是把它隐藏在这个方法中。