波波老师好,我想问一个创建泛型数组强制转换的问题。

来源:2-6 使用泛型

慕虎3444883

2018-10-11

Exception in thread “main” java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at First.main(First.java:26)
在波波老师的介绍后,写作业用到了这个Object[]强制转换为E[],但是不知道为什么运行的时候会报这个 类型转换错误。我觉得跟您讲的数组中用到的差不多呀?
ps:这个小算法是我的作业,用来删除顺序表中从index开始的amount个元素。。如果我把返回值弄成Object[]的话 后边也相应的改成Object[],就可以正常输出了。但是这样数组就不是原来的类型了,就逃避开了这里的问题。。
图片描述

写回答

1回答

liuyubobobo

2018-10-12

问题没有出在你的第4行,而是在20行。简单地说,返回的newArray是Object[]类型,而不是Integer[]类型。你的代码和我的课程中的代码的区别在于,我的课程中的代码,从来不会返回一个泛型数组,只会返回一个泛型值。而泛型值和泛型数组,在Java编译器的处理上,有巨大的差异。Java可以自动把泛型值转换成对应的类型,但无法把一个泛型数组自动转换成对应类型的泛型数组。


这不是什么出色的语言特性,在我看来完全属于java语言的坑!要知道,泛型这种语言特性是在Java 5以后才有的,而不是在Java语言设计之初就支持的一种原生语言特性,可能是这个原因,导致Java语言在一些高级特性的使用上(不仅仅是泛型),其实是很不流畅的。。。


Anyway,如果你想返回的是一个泛型数组,到底要怎么做?


1)不使用Java的内置数组,而是自己包装一个MyArray,返回一个新的MyArray。代码类似这样:

public MyArray<E> deleteFrom(MyArray<E> array, int index){
    MyArray<E> newArray = new MyArray<E>(array);
    newArray.remove(index);
    return newArray;
}


2)如果使用Java的内置数组,就需要明确告诉这个函数E是什么类型,比如这样:

public E[] deleteFrom(E[] arr, Class<E> clazz){
   // 复制了一份 newArray
    E[] newArray = (E[]) Array.newInstance(clazz, arr.length);
    for(int i = 0; i < arr.length; i ++)
        newArray[i] = arr[i];
    
    // 进行你的逻辑 
    // ...
    
    return newArray;
}


此时,调用应该是这样的:

Integer[] res = first.deleteFrom(arr, Integer.class);


加油!:)

2
2
liuyubobobo
回复
慕虎3444883
方法2其实返回的是clazz类型的数组,因为使用Array.newInstance构造的时候,显示声明了这个数组中的元素类型是clazz。只不过返回值的类型,由于我们不知道传入的clazz类型是什么,所以用E[]表示。你可以近似地理解成这是一种多态(虽然和严格意义的多态不一样)。你的代码,其实也是因为不知道返回什么类型,所以返回的是Object[]。因为Object是所有类型的父类。get不到这个方法的精髓很正常。因为这本身在我看来,就属于Java的高级语法知识。简单理解,就是Java在处理内建的数组,和处理单独的变量,机制极其不一样。所以,我更建议使用方法1。方法1说白了,就是避开了直接使用Java内置数组,而将他们包裹在类中。返回值变成了单独的类,而非数组:)
2018-10-12
共2条回复

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1704 问题

查看课程