簡體   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