Java:对泛型进行类型转换

时间:2010-05-12 04:02:37

标签: java generics class casting

此方法使用方法级泛型,它解析自定义POJO JXlistOfKeyValuePairs中的值(正是如此)。唯一的问题是JXlistOfKeyValuePairs中的键和值都是String s。

除了JXlistOfKeyValuePairs实例之外,此方法还需要Class<T>来定义将值转换为哪种数据类型(假设只有Boolean,{{1} }}和Integer是可能的)。然后,它为其条目中的值输出具有指定类型的Float

这是我所拥有的代码,它显然已被破坏。

HashMap

这是我要解决的问题:

private <T extends Object>  Map<String, T>
    fromListOfKeyValuePairs(JXlistOfKeyValuePairs jxval, Class<T> clasz)
{
    Map<String, T> val = new HashMap<String, T>();
    List<Entry> jxents = jxval.getEntry();
    T value;
    String str;
    for (Entry jxent : jxents)
    {
        str = jxent.getValue();
        value = null;
        if (clasz.isAssignableFrom(Boolean.class))
        {
            value = (T)(Boolean.parseBoolean(str));
        } else if (clasz.isAssignableFrom(Integer.class))
        {
            value = (T)(Integer.parseInt(str));
        } else if (clasz.isAssignableFrom(Float.class))
        {
            value = (T)(Float.parseFloat(str));
        }
        else {
            logger.warn("Unsupported value type encountered in key-value pairs, continuing anyway: " +
                clasz.getName());
        }
        val.put(jxent.getKey(), value);
    }
    return val;
}

我得到:if (clasz.isAssignableFrom(Boolean.class)) { value = (T)(Boolean.parseBoolean(str)); } else if (clasz.isAssignableFrom(Integer.class)) { value = (T)(Integer.parseInt(str)); }

此外,如果可能的话,我希望能够使用更优雅的代码执行此操作,避免使用Class#isAssignableFrom。

有什么建议吗?


示例方法调用:

Inconvertible types required: T found: Boolean

解决了,感谢@Chris Dolan和@polygenelubricants。原因是当与原语的自动装箱结合时,类型转换变得混乱。避免编译器警告,因为方法参数Map<String, Boolean> foo = fromListOfKeyValuePairs(bar, Boolean.class); 的类型为clasz,而不仅仅是Class<T>Class,因此调用Class<?>方法是类型安全的。

默认地将Impl。溶液:

cast

3 个答案:

答案 0 :(得分:5)

您可以使用Class<T>.cast方法,而不是自己进行未经检查的(T)演员。

    if (clasz.isAssignableFrom(Boolean.class)) {
        value = clasz.cast(Boolean.parseBoolean(str));
    } else if (clasz.isAssignableFrom(Integer.class)) {
        value = clasz.cast(Integer.parseInteger(str));
    } else if (clasz.isAssignableFrom(Float.class)) {
        value = clasz.cast(Float.parseFloat(str));
    }

没有编译器警告。


至于为什么原始代码不能编译,这是因为你试图将原始直接转换为未知的引用类型。将直接从基元转换为引用类型仅适用于非常特殊的情况,在所有这些情况下,类型必须在编译时已知

    Object o;

    o = (Integer) 42; // works! Boxing conversion!
    o = (Number) 42;  // works! Autoboxing then widening reference conversion!
    o = (Object) 42;  // works! Autoboxing then widening reference conversion!
    o = 42; // YES! This also compiles!!!

    o = (String) ((Object) 42); // compiles fine!
    // will throw ClassCastException at run-time

    o = (String) 42; // DOESN'T COMPILE!!!

最后一行类似于从基元直接转换为未知参数化类型T(即(T) Integer.parseInt(s)),这就是它无法编译的原因。确实,您正在尝试编写代码,使T成为正确的类型,但在编译时无法确认,因为T通常可以是任何类型。 / p>

前一行到达编译时错误,间接将原语转换为String,之后已将其转换为Object引用类型。这就是它编译的原因,当然它会在运行时抛出ClassCastException

这是一个参数化类型的通用示例:它有点傻,但重新演示了将原语直接转换为未知引用类型的问题:

<T> T f() {
    //return (T) 42; // DOESN'T COMPILE!!!
    return (T) (Integer) 42; // compiles with warning about unchecked cast
}

参考

答案 1 :(得分:2)

这是你想要的:

    if (clasz.isAssignableFrom(Boolean.class))
    {
        value = (T)Boolean.valueOf(Boolean.parseBoolean(str));
    } else if (clasz.isAssignableFrom(Integer.class))
    {
        value = (T)Integer.valueOf(Integer.parseInt(str));
    } else if (clasz.isAssignableFrom(Float.class))
    {
        value = (T)Float.valueOf(Float.parseFloat(str));
    }

问题是您的代码愚弄了自动装箱,因此编译器没有自动将原始boolean转换为Boolean实例。我提出了明确的转换和瞧。代码抱怨未经检查的演员阵容,但这是不可避免的,所以你想要@SuppressWarnings

答案 2 :(得分:0)

最简单的解决方案可能只是将事物(特别是值变量和地图)视为对象,然后在方法返回时对(T)进行最终强制转换。

你会得到一堆未经检查的警告,但无论如何你都会得到那些......