繁体   English   中英

未经检查的从对象到列表的转换

[英]Unchecked cast from Object to List

我正在尝试扩展此处发布的问题的解决方案。

在那里共享的castList方法对于非泛型类型非常有用。

public static <T> List<T> castList(Object obj, Class<T> clazz)
{
    List<T> result = new ArrayList<T>();
    if(obj instanceof List<?>)
    {
        for (Object o : (List<?>) obj)
        {
            result.add(clazz.cast(o));
        }
        return result;
    }
    return null;
}

当返回类型不是简单的字符串列表,而是列表本身是另一个泛型(例如地图列表)时,我们遇到的问题就是尝试使用相同的想法。

List<Map<String, Object>> list = (List<Map<String, Object>>) out.get("o_cursor");

尝试按以下方式使用castList会导致类型不匹配:无法从List <Map>转换为List <Map <String,Object >>。 有没有办法扩展castList来做到这一点?

List<Map<String, Object>> list = castList(out.get("o_cursor"), Map.class);

我尝试了特定于地图列表的修改版本,但仍然收到错误消息“方法castMapList(Object,Class <Map <K,V >>)不适用于参数(Object,Class <Map>)”像是同一错误的不同风味。

public static <K, V> List<Map<K, V>> castMapList(Object object, Class<Map<K, V>> clazz) {        
    if (object instanceof List<?>) {
        List <Map<K, V>> result = new ArrayList<Map<K, V>>();

        for (Object o: (List<?>) object) {
            result.add(clazz.cast(o));
        }

        return result;
    }

    return null;
}

由于擦除,存在:

  1. 无法拥有Class<Map<K, V>>
  2. 没有内置的方法可以在运行时检查每个Map是否具有特定的KV

那是:

  1. 如您Map.class ,每个泛型类都有一个对应的原始类型Class对象,例如Map.classClass<Map>
  2. 诸如obj instanceof Map<K, V> Class东西是编译器错误,并且Class对象不使用isInstancecast检查通用参数。

值得一提的是,如果没有一些额外的工作,您将无法在运行时验证泛型。

您仍然可以围绕它进行编程,具体取决于您在做什么。 例如,一种简单的方法就是重建每个Map ,就像重建List

static <K, V> List<Map<K, V>> castMapList(
        Object obj, Class<K> keyType, Class<V> valueType) {
    if (obj instanceof List<?>) {
        List<Map<K, V>> result = new ArrayList<>();

        for (Object element : (List<?>) obj) {
            if (element instanceof Map<?, ?>) {
                Map<K, V> map = new HashMap<>();

                for (Map.Entry<?, ?> entry : (Map<?, ?>) element) {
                    map.put(keyType.cast(entry.getKey()),
                            valueType.cast(entry.getValue());
                }

                result.add(map);
            } else {
                // do something that you want?
                // personally I would throw ClassCastExceptions
                // but you seem to be returning null
            }
        }

        return result;
    }
    return null;
}

另外,例如,看起来您似乎正在进行某种反序列化,并且可以将Class烘烤到要序列化的Map中:

public class MyCheckedMap<K, V>
extends SomeMapImplementation<K, V>
implements Serializable {
    private static final long serialVersionUID = 1L;
    private final Class<K> keyType;
    private final Class<V> valueType;

    public MyCheckedMap(Class<K> keyType, Class<V> valueType) {
        this.keyType = Objects.requireNonNull(keyType);
        this.valueType = Objects.requireNonNull(valueType);
    }

    @SuppressWarnings("unchecked")
    public static <K, V> MyCheckedMap<K, V> cast(
            Object obj, Class<K> keyType, Class<V> valueType) {
        if (!(obj instanceof MyCheckedMap<?, ?>))
            throw new ClassCastException(obj.getClass().toString());

        MyCheckedMap<?, ?> map = (MyCheckedMap<?, ?>) obj;
        validate(keyType, map.keyType);
        validate(valueType, map.valueType);

        return (MyCheckedMap<K, V>) obj;
    }

    private static void validate(Class<?> lhs, Class<?> rhs) {
        if (lhs == rhs)
            return;
        throw new ClassCastException(String.format("%s != %s", lhs, rhs));
    }
}

您必须为每个ListMap等编写一些样板代码,但可能只做不到。

还有其他一些方法可以解决此类问题,例如Neal Gafter的Super Type Tokens和Guava的TypeToken ,这是Neal Gafter的思想的衍生。 这些本质上使用反射来实现MyCheckedMap类的MyCheckedMap

我不确定是否存在未经检查的警告对您来说是否是一个问题。 对于地图,您可以执行以下操作:

public <K, V> List<Map<K, V>> castMapList(Object object, Class<K> class1, Class<V> class2) {
    if (object instanceof List<?>) {
        List<Map<K, V>> result = new ArrayList<>();

        for (Map<K, V> o : (List<Map<K, V>>) object) { //Unchecked cast
            result.add(o);
        }

        return result;
    }

    return null;
}

要么

for (Object o : (List<?>) object) {
    if (o instanceof Map<?, ?>) {
        result.add((Map<K, V>) o); //Unchecked cast
    }
}

我认为对您来说,不发出抑制警告是最糟糕的情况,因为即使在Class.javacast方法中 ,他们也会这样做。 您必须确保列表中包含地图。

这就是我想出的。 再次感谢!

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CastUtility {

    public static <T> List<T> castList(Object object, Class<T> clazz) {
        if (object == null) {
            return null;
        }

        if (object instanceof List<?>) {
            List<T> result = new ArrayList<T>();

            for (Object o : (List<?>) object) {
                result.add(clazz.cast(o));
            }

            return result;
        }

        throw new ClassCastException();
    }

    public static <K, V> Map<K, V> castMap(Object object, Class<K> keyType,
            Class<V> valueType) {

        if (object == null) {
            return null;
        }

        if (object instanceof Map<?, ?>) {
            Map<K, V> result = new HashMap<K, V>();

            for (Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
                result.put(keyType.cast(entry.getKey()),
                        valueType.cast(entry.getValue()));
            }

            return result;
        }

        throw new ClassCastException();
    }

    public static <K, V> List<Map<K, V>> castMapList(Object object,
            Class<K> keyType, Class<V> valueType) {

        if (object == null) {
            return null;
        }

        if (object instanceof List<?>) {
            List<Map<K, V>> result = new ArrayList<Map<K, V>>();

            for (Object o : (List<?>) object) {
                result.add(castMap(o, keyType, valueType));
            }

            return result;
        }

        throw new ClassCastException();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM