代码之家  ›  专栏  ›  技术社区  ›  0xh3xa Neha

为什么创建泛型列表时没有在运行时绑定正确的数据类型?

  •  0
  • 0xh3xa Neha  · 技术社区  · 6 年前

    我试图创建一个泛型方法,该方法返回具有给定数据类型的泛型列表。

    我通过了 Integer 作为数据类型,我填写了 String

    我的问题是为什么我没有收到 ClassCastException 在运行时?

        public static void main(String[] args) {
            List<Integer> list = (List<Integer>) generic(Integer.class);
            System.out.println(list);
        }
    
        private static <T> List<?> generic(T clazz) {
            List<T> list = new ArrayList<>();
            list.add((T) Arrays.asList("create", "generic"));
            list.add((T) Arrays.asList("create", "generic2"));
            return list;
        }
    

    输出

    [[create, generic], [create, generic2]]
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Holger    6 年前

    由于 type erasure 堆污染

    List<Integer> 无论如何,这是错误的。你通过了 Integer.class 作为 T clazz T 不是 Integer 但是 Class<Integer> .

    正确的通用声明应为:

    public static void main(String[] args) {
        List<Integer> list = generic(Integer.class);
        System.out.println(list);
    }
    
    private static <T> List<T> generic(Class<T> clazz) {
        List<T> list = new ArrayList<>();
        return list;
    }
    

    既然程序没有未检查的警告,您就可以确保在运行时不会发生堆污染。如果你想要更多的保证,你可以使用

    public static void main(String[] args) {
        List<Integer> list = generic(Integer.class);
        System.out.println(list);
    }
    
    private static <T> List<T> generic(Class<T> clazz) {
        List<T> list = Collections.checkedList(new ArrayList<>(), clazz);
        list.add((T) Arrays.asList("create", "generic")); // will fail at runtime
        list.add((T) Arrays.asList("create", "generic2"));
        return list;
    }
    

        2
  •  0
  •   Tom Hawtin - tackline    6 年前

    正如你宣布的那样 T <T> (T) 反对 Object List 很好。

    List<E> ,因此不能从中进行额外的内部运行时类型检查 List.add List.toString .

    但是,您将得到警告(只要在编译器中启用了lint选项)。不要忽视这些警告。

    clazz.cast 代替 不能使用参数化类型。

        3
  •  0
  •   Kirill Simonov    6 年前

    在编译过程中被编译器擦除 Type Erasure . 因此,在类型擦除之后,您的方法将如下所示:

    private static List generic(Object clazz) {
        List list = new ArrayList();
        list.add((Object) Arrays.asList("create", "generic"));
        list.add((Object) Arrays.asList("create", "generic2"));
        return list;
    }
    

    main 方法将如下所示:

    List list = (List) generic(Integer.class);
    System.out.println(list);
    

    ClassCastException 被扔掉,因为你不想做任何事 Integer 对列表中的元素执行特定操作。但你会尽快得到它,例如:

    list.forEach(integer -> System.out.println(integer.intValue()));
    

    ArrayList 整数 召唤 intValue() .

    将泛型与未经检查的强制转换一起使用是毫无用处的。