这段代码smells。是的,这在 Java 7 下通过了,是的,它在 Java 7 中运行正常,但是有一些东西绝对错误 here.
首先,我们来谈谈这个泛型类型。
@SuppressWarnings("unchecked")
public <T> T getProperty(String name) {
return (T) properties.get(name);
}
你能一眼看出什么T
should是?如果我在 Java 7 合规模式下使用 IntelliJ 在该行运行这些转换,我会得到这非常有帮助的信息ClassCastException
:
Cannot cast java.util.Date to T
因此,这意味着在某种程度上,Java 知道这里有问题,但它选择更改该转换,而不是从(T)
to (Object)
.
@SuppressWarnings("unchecked")
public <T> Object getProperty(String name) {
return (Object) properties.get(name);
}
在这种情况下,演员阵容是多余的,你会得到一个Object
正如您所期望的,从地图上可以看到。然后,调用正确的重载。
现在,在 Java 8 中,事情变得更加理智了;因为你并没有真正提供类型getProperty
方法,它爆炸了,因为它really无法投射java.util.Date
to T
.
最后,我掩盖了要点:
泛型的这种使用是错误的并且是错误的。
你甚至不need这里泛型。您的代码可以处理String
or an Object
,而你的地图只包含Object
无论如何。
你应该只返回Object
来自getProperty
方法,因为无论如何你只能从地图返回。
public Object getProperty(String name) {
return properties.get(name);
}
这确实意味着您不再能够拨打电话directly进入签名为的方法String
(因为你正在通过Object
现在),但这确实意味着您损坏的泛型代码最终可以得到解决。
If you really不过,想要保留这种行为,您必须在函数中引入一个新参数,该参数实际上允许您指定想要从映射返回哪种类型的对象。
@SuppressWarnings("unchecked")
public <T> T getProperty(String name, Class<T> clazz) {
return (T) properties.get(name);
}
然后你可以这样调用你的方法:
StringUtils.isNullOrEmpty(props.getProperty("value", Date.class));
现在我们绝对确定什么T
是的,Java 8 对此代码很满意。这仍然有点气味,因为你把东西存放在一个Map<String, Object>
;如果你有Object
重写方法,您可以保证该映射中的所有对象都具有有意义的toString
,那么我个人会避免使用上面的代码。