我正在编写自己的双链表实现。
我找到了方法public <T> T[] toArray(T[] a)
public <T> T[] toArray(T[] a) {
if (a.length < size()) {
T[] array = (T[]) new Object[size()];
Node temp = head;
int currentIndex = 0;
while (currentIndex < size) {
a[currentIndex] = (T) temp.data;
currentIndex++;
temp = temp.next;
}
}
if (a.length > size()) {
a[size] = null;
}
Node temp = head;
for (int i = 0; i < size; i++) {
a[i] = (T) temp.data;
temp = temp.next;
}
return a;
}
我正在用测试它
List<String> list = new DoubleLinkedList<String>();
list.add(0, ("0"));
list.add(1, ("1"));
list.add(2, ("2"));
list.add(3, ("3"));
list.add(4, ("4"));
list.add(5, ("5"));
String array[] = list.toArray(new String[6]);
for (int i = 0; i < list.size(); i++) {
System.out.println(array[i]);
}
当我用String array[] = list.toArray(new String[6]);
或String array[] = list.toArray(new String[7]);
或任何更高的数字测试它时,它就工作了。但如果我使用String array[] = list.toArray(new String[5]);
或更低的版本进行测试,则不会打印出任何结果。JUnit抛出一个ClassCastException。
请帮我弄清楚。
第1版:更改了一些不相关的代码。
这:
T[] array = (T[]) new Object[size()];
由于Foo[]
和ArrayList<Foo>
之间的重要区别。对于ArrayList<Foo>
,new ArrayList<Foo>()
创建的实际实例只是一个ArrayList
;<Foo>
是一些编译器的聪明之处,可以帮助您跟踪类型,但它在运行时会消失。然而,对于new Foo[10]
,实际创建的实例知道其类型是Foo[]
。例如,就编译器而言,这个代码片段是完全有效的,并在运行时引发一个ClassCastException
:
Object[] objectArray = new Integer[10];
String[] stringArray = (String[]) objectArray;
而具有ArrayList
的类似代码将被编译器拒绝(并且,如果编译器允许,则不能在运行时检查)。
因此,T[] array = (T[]) new Object[size()];
的问题是,T
通常不会是Object
(在您的情况下,它恰好是String
),因此new Object[]
通常不会成为T[]
的实例。
ClassCastException
不会出现在这一有问题的行,因为与泛型相关的类型擦除意味着编译器实际上无法检查这一行的强制转换;相反,编译器会在第一次获得机会时插入一个隐式强制转换。这就是—它隐式地转换这一行:
String array[] = list.toArray(new String[6]);
到此:
String array[] = (String[]) list.toArray(new String[6]);
它失败了,因为当list.toArray
承诺返回String[]
时,您偷偷地欺骗它构造了一个Object[]
。
要解决此问题,您需要使用a
的组件类型,并使用一点点反射创建相应阵列类型的新实例:
T[] array = (T[]) Array.newInstance(a.getClass().getComponentType(), size());