代码之家  ›  专栏  ›  技术社区  ›  bguiz

Java:泛型类型化

  •  2
  • bguiz  · 技术社区  · 15 年前

    该方法使用方法级泛型,解析来自自定义POJO的值, JXlistOfKeyValuePairs (正是这样)。唯一的问题是 JXListofkeyValuePairs(JXListofkeyValuePairs) String S.

    除了 JXListofkeyValuePairs(JXListofkeyValuePairs) 实例,A Class<T> 它定义要将值转换为的数据类型(假定只有 Boolean , 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));
    }
    

    我得到: Inconvertible types required: T found: Boolean

    另外,如果可能的话,我希望能够使用更优雅的代码来完成这项工作,避免类isassignablefrom。

    有什么建议吗?


    示例方法调用:

    Map<String, Boolean> foo = fromListOfKeyValuePairs(bar, Boolean.class);
    

    解决了,感谢@chris dolan和@polygene润滑剂。原因是,当与原始人的自动氧化结合在一起时,打字变得混乱。避免编译器警告,因为方法参数 clasz 属于这种类型 课堂教学; 而不是仅仅 Class Class<?> ,因此调用 cast 方法是类型安全的。

    IMPL索尔纳:

    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 = clasz.cast(Boolean.parseBoolean(str));
            }
            else if (clasz.isAssignableFrom(Integer.class))
            {
                value = clasz.cast(Integer.valueOf(Integer.parseInt(str)));
            }
            else if (clasz.isAssignableFrom(Float.class))
            {
                value = clasz.cast((Object)Float.parseFloat(str));
            }
            else
            {
                logger.warn("Unsupporteded value type encountered in key-value pairs, continuing anyway: " +
                    clasz.getName());
            }
            val.put(jxent.getKey(), value);
        }
        return val;
    }
    
    3 回复  |  直到 15 年前
        1
  •  5
  •   polygenelubricants    15 年前

    你可以使用 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 通常可以是任何类型。

    前一行到最后一行通过 间接地 将原语强制转换为 String ,在它已转换为 Object 引用类型。这就是它编译的原因,尽管它当然会 ClassCastException 在运行时。

    下面是一个参数化类型的通用示例:这有点愚蠢,但是重新考虑了转换原语的问题。 直接地 到未知的引用类型:

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

    工具书类

        2
  •  2
  •   Chris Dolan    15 年前

    以下是您想要的:

        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 到A Boolean 自动执行实例。我输入了明确的转换,瞧。代码抱怨未经检查的强制转换,但这是不可避免的,因此您需要@suppresswarnings

        3
  •  0
  •   Steven Schlansker    15 年前

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

    你会收到一堆未经检查的警告,但不管怎样,你还是会得到那些…