首页 > 解决方案 > 奇怪的 Java 类型安全不适用于集合

问题描述

  public static <T> List<T> toArray(JSONArray array) {
        if(array == null) {
            return Collections.emptyList();
        }

        List<T> o = new ArrayList<>();

        for(int i=0, l = array.length(); i < l; i++) {
            o.add((T) array.get(i));
        }

        return o;
    }

    public static void test() {
        List<Object> values = new ArrayList<>();
        values.add("Product");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("key", values);
        List<Long> test = new ArrayList<>();
        test = toArray((JSONArray) jsonObject.get("key"));
        System.out.println(test);
    }

上面的代码允许将String值存储在 a 中List<Long>,这完全是荒谬的。任何帮助非常感谢?

标签: javajava-8

解决方案


这一行:

o.add((T) array.get(i));

将生成未经检查的强制转换警告。

未经检查的强制转换是编译器无法插入checkcast字节码指令来检查它是否真的是您要强制转换的类型的实例的强制转换。它不能在这里这样做,因为它不知道什么T是“是”。

你只是在做一些不安全的事情。除非您取消了警告,否则您将收到警告(这不是一个好主意,因为您不会被告知要做不安全的事情)。

这就是 Java 的工作方式。


您可以通过传入 a Function<Object, T>(或更一般地说,Function<Object, ? extends T>)作为参数来安全地执行此操作:

public static <T> List<T> toArray(JSONArray array, Function<Object, ? extends T> checker) {
  // ...
  o.add(checker.apply(array.get(i)));
  // ...
}

现在,确保它是 a 的责任T被委托给checker:您可以调用此方法,例如:

test = toArray((JSONArray) jsonObject.get("key"), Long.class::cast);

如果元素不是Long.


推荐阅读