我有一个完整的绊脚石,并向你们所有人提出,看看你是否知道发生了什么。
这是数据结构
Map<String, Object> objectMap
它现在存储字符串和数值,但将来可能会存储更多类型。
这是我用来检索这些值的函数:
public <T> T get(String variable, T defaultValue) {
// returns either the object from the map, or the default if its not in the map.
Object value = getObject(variable, defaultValue);
logger.debug("default value is of type " + defaultValue.getClass().getName());
// Attempt to get around casting issue
if (value instanceof Number)
{
value = (Number) value;
}
T ret = (T) value;
logger.debug("Variable " + variable + " which is of type " + value.getClass().getName() + " and returning as " + ret.getClass().getName() + " (is number: " + (value instanceof Number) + ")");
return ret;
}
这是调用代码:
public int getFoo() { return this.<Integer>get("foo", 0); }
这是我在日志中看到的输出:
default value is of type java.lang.Integer
Variable foo which is of type java.lang.Long and returning as java.lang.Long (is number: true)
在它失败之前:
java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer
我最关心的是类类型似乎是Long,尽管试图强制类使用Integer 。
我是否遗漏了某些内容,或者违反了Java泛型的某些概念?
感谢您的帮助
答案 0 :(得分:2)
getObject
方法返回的值是java.lang.Long
- 日志告诉你。
泛型不是魔术,它们不会在类型之间转换,它们只是编译器转变为强制转换的语法糖。所以你的方法:
public <T> T get(String variable, T defaultValue)
真的是:
public Object get(String variable, Object defaultValue)
使用以下方法调用get方法时
this.<Integer>get("foo", 0)
这是真的:
(Integer)this.get("foo", 0)
因此ClassCastException是因为返回的Object
是Long
,而不是Integer
。
如果不确切地知道你想要实现什么,很难给出具体的建议,但通常你的Map
应该使用你期望处理的泛型类型。在您的情况下,这听起来像Integer
或Number
。如果你真的想要任何Number
的int值(我怀疑因为当它大于int时该值会被截断)那么你应该使用Number.intValue()
方法。
答案 1 :(得分:0)
这是由Java类型擦除引起的。 Java类型仅用于源代码。编译器会像转换所有对象一样转换代码。如果获得Long值,则表示将其设置为Long值。
此代码不执行任何操作:
if (value instanceof Number)
{
value = (Number) value;
}
答案 2 :(得分:0)
支持地图中的键“foo”的值显然是Long类型。您不能将Long转换为整数(即使两者都是Number类型 - 并且都是Object类型;)
如果要强制使用Integer,则必须在将“foo”的值放入地图时执行此操作。