以下两种将集合转换为数组对象的方法的根本区别
ArrayList<String> iName = new ArrayList<String>();
String[] array= iName.toArray(new String[iName.size()]);//1
String[] array= iName.toArray(new String[0]);//2
什么时候应该使用approach-1和何时接近-2?
答案 0 :(得分:4)
第一种方法更好,因为您创建了一个数组,toArray
使用它来存储输入列表的元素。第二种方法导致toArray
创建另一个数组,因为它不能在空数组中存储任何内容。
如果将长度大于输入列表大小的数组传递给方法,则会遇到不同的行为,因为在这种情况下,数组的size
元素(其中{{ 1}}是输入列表的大小)将被指定为null。
如果在调用方法时没有实例化数组,而是使用预先存在的数组,那么将一个小于列表大小的数组传递给方法是唯一有意义的时间:
size
此处您事先并不知道array = iName.toArray(array);
是否足够大以包含array
的元素。如果不是,iName
将返回一个新数组。如果是,toArray
将返回输入数组。
答案 1 :(得分:2)
这两种方法之间的区别:
String[] array = iName.toArray(new String[iName.size()]);
String[] array = iName.toArray(new String[0]);
如果有可能同时修改源集合(在这种情况下为iName
),则完全不同。如果不存在并发的可能性,那么第一行是可取的。
这并不严格适用于您的示例,其中源集合为ArrayList
,这不是线程安全的。但是,如果源集合是并发集合,则并发修改下的行为很重要。在这种情况下,第一行具有竞争条件。调用线程首先得到大小;然后,另一个线程可能会添加或删除元素,从而更改其大小。但是调用线程使用旧大小分配数组并将其传递给toArray
。
这不会导致错误。如果您仔细阅读Collection.toArray(T[])
的规范,则这些案例是明确定义的。如果集合已经增长,将为其分配一个新阵列,使得调用者的阵列分配变得多余。如果集合已缩小,则数组的尾部将以null元素结束。这不一定是错误,但是任何使用结果数组的代码都必须准备好处理空值,这可能会令人不快。
传递零长度数组避免了这些问题,可能会分配无用的零长度数组。 (可以保留一个缓存版本,但它会增加混乱。)如果集合为空,则只返回零长度数组。但是,如果集合具有元素,则集合本身会分配正确大小的数组并填充它。这避免了呼叫者交出一个错误的#34;大小
在Java 8 Streams API中,Stream.toArray
方法通过让调用者在数组工厂中传递来避免此问题。这允许调用者指定类型,但允许集合指定适当的大小。尽管如此,这还没有被改装到Collections
。这由RFE JDK-8060192涵盖。
答案 2 :(得分:0)
基本上两种方法都做同样的事情,并会产生相同的输出,但在引擎盖下它们的行为有点不同。
在第一种方法中,由于数组的大小足够大,List可以将其项目复制到数组并返回相同的数据。当您使用第二种方法时,List类所做的几乎与您的第一种方法完全相同:创建一个具有正确大小的新数组来复制值。
从效率的角度来看:在第一种方法中,创建一个不使用的阵列,即使创建阵列也不会花费太多时间或处理能力,但这不是一件好事,但它是多余的,不应该这样做。如果您知道列表的大小,所有集合都知道它们的大小,您应该使用第一种方法。
答案 3 :(得分:0)
如果你看一下实现,你可以理解其中的区别:
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;
}
如果提供的数组小于ArrayList,则会创建一个新数组。如果提供的数组大于ArrayList,它将用于复制列表的后备数组的内容。
就性能而言,最佳做法是使用第一种方法(iName.toArray(new String[iName.size()])
),但第二种方法的惩罚并不大(创建0大小的数组)。
我个人使用第二种方法,因为我认为它使代码更具可读性。