假设我有一个数组列表
ArrayList<MyClass> myList;
我想调用toArray,是否有性能方面的原因
MyClass[] arr = myList.toArray(new MyClass[myList.size()]);
over
MyClass[] arr = myList.toArray(new MyClass[0]);
?
我更喜欢第二种风格,因为它不那么冗长,而且我假设编译器将确保不会真正创建空数组,但我一直在想这是否属实。
当然,在99%的情况下,它不会以某种方式或其他方式产生区别,但我希望在我的普通代码和优化的内部循环之间保持一致的风格……
第一种情况更有效。
这是因为在第二种情况下:
MyClass[] arr = myList.toArray(new MyClass[0]);
运行时实际上创建了一个空数组(大小为零),然后在toArray方法中创建另一个数组以适应实际数据。这个创建是使用下面的代码(来自jdk1.5.0_10)通过反射完成的:
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.
newInstance(a.getClass().getComponentType(), size);
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
通过使用第一种形式,可以避免创建第二个数组,也可以避免反射代码。
从Java 5中的ArrayList开始,如果数组的大小合适(或更大),它就会被填充。因此
MyClass[] arr = myList.toArray(new MyClass[myList.size()]);
将创建一个数组对象,填充它并返回给"arr"。另一方面
MyClass[] arr = myList.toArray(new MyClass[0]);
将创建两个数组。第二个是长度为0的MyClass数组。这里有一个对象创建用于一个马上会被丢弃的对象。就源代码所示,编译器/ JIT无法优化这个对象,因此不会创建它。此外,使用零长度对象会导致在toArray() -方法中进行强制转换。
请参阅ArrayList.toArray()的源代码:
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
使用第一种方法只创建一个对象,并避免(隐式但代价昂贵的)强制类型转换。
第一种情况更有效。
这是因为在第二种情况下:
MyClass[] arr = myList.toArray(new MyClass[0]);
运行时实际上创建了一个空数组(大小为零),然后在toArray方法中创建另一个数组以适应实际数据。这个创建是使用下面的代码(来自jdk1.5.0_10)通过反射完成的:
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.
newInstance(a.getClass().getComponentType(), size);
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
通过使用第一种形式,可以避免创建第二个数组,也可以避免反射代码。