未能强制输入java泛型

时间:2012-03-05 08:07:41

标签: java generics casting

我有一个完整的绊脚石,并向你们所有人提出,看看你是否知道发生了什么。

这是数据结构

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泛型的某些概念?

感谢您的帮助

3 个答案:

答案 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是因为返回的ObjectLong,而不是Integer

如果不确切地知道你想要实现什么,很难给出具体的建议,但通常你的Map应该使用你期望处理的泛型类型。在您的情况下,这听起来像IntegerNumber。如果你真的想要任何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”的值放入地图时执行此操作。