Java - 实现动态大小对象数组的最佳方法

12

我是一名Java的初学者。

我需要实现一个在执行期间大小会改变的对象数组。

我正在编写的代码也将被移植到Android上。

根据您的经验,最好使用哪个类来实现它?

谢谢,


2
不了解需求很难回答。请查看http://download.oracle.com/javase/tutorial/collections/index.html,看看哪个符合要求。 - Oliver Charlesworth
为什么不使用API中的ArrayList等呢? - dacwe
4个回答

22

Java的模板功能不太完善。只要你想要一个对象数组,那么ArrayList<T>就很好用。但对于原始类型来说,它很糟糕。

假设您有一个想要放入列表中的对象层次结构,那么ArrayList是理想的选择:

ArrayList<Vehicle> vehicles = new ArrayList<Vehicle>();

vehicles.add(new Car(...));
vehicles.add(new Truck(...));

我假设在上面的例子中,Vehicle是基类,而Car和Truck是它的子类。

另一方面,如果你想要一个数字列表,Java非常低效。每个对象都是对12字节内存块的引用(实际上是4字节指针),再加上你实际使用的部分。由于ArrayList不能应用于int,这意味着创建数字列表需要:

  1. 创建Integer列表,int的对象包装器。
  2. 每次获取一个数字时转换对象。现在这是自动完成的,但需要时间。
  3. 初始化5倍所需存储空间。

因此,如果你正在处理大量的原始数据(int、float、double),编写自己的ArrayList版本可能会有所帮助。当数据很大而平台很小(比如手持Android设备)时,这尤其重要。

将此与下述内容进行比较:

ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 1000000; i++)
  list.add(i):

至:

public class IntArray {
private int[] data;
private int used;
private void grow() {
 // implement code to make data double in size here...
}
public IntArray(int size) {
  data = new int[size];
  used = 0;
}

public void add(int i) {
  if (i >= data.length) grow();
  data[used++] = i;
}
}

IntArray list2 = new IntArray(1000000);
for (int i = 0; i < 1000000; i++)
  list2.add(i);

当我进行基准测试时,使用原始列表的最佳方法比明显不太理想的ArrayList用法快多达10倍以上。为了更加公正,将ArrayList预先分配到正确的大小-它仍然要慢得多。

如果您要在列表的开头或中间插入数据,则LinkedList才值得使用。如果您的列表是通过添加到末尾来构建的,则ArrayList会彻底占据优势。因此,对于按顺序构建的典型对象列表,ArrayList是您正在寻找的内容。对于像int或double这样的大型原语列表,请编写自己的列表。


虽然相对于ArrayList,使用LinkedList的情况可能很少,但它们确实存在,并且在这些情况下,LinkedList的性能可以显著提高。列表的队列使用是一个例子...与LinkedList相比,从ArrayList的前面删除非常昂贵。请参见 - ColinD
@Colin,使用ArrayList而不是LinkedList可能确实是一件坏事。但是,如果你想要一个更快的队列,那么我敢打赌,一个具有指定头/尾的循环队列的实现将大幅击败LinkedList——即使你可以在需要时使其增长,平均情况下也只是将对象放置在已经存在的列表中。是的,在ArrayList开头插入是昂贵的。 - Dov

11

3

您应该熟悉Java中的集合框架。您将会遇到像Set、List、Map、SortedSets等非常有用的数据结构。


0

这取决于你将用它来做什么。

如果你有一个经常改变大小的数组,那么我建议使用 ArrayList 或者其他集合框架中的东西(根据你将要使用的内容而定)。

然而,如果你有一个很少改变大小但是经常被读取的数组,可能更快的方法是使用普通的数组,需要时再调整大小。

Arrays.copyOf(array, newSize);

希望能有所帮助!:)

虽然原始数组有时候最好,但在Java中使用对象数组没有任何好的理由。 "它可能会更快" ... 这是过早的优化。 - ColinD
使用原始类与硬编码数组的编写方式不同。而且人们过于关注避免“过早优化”,而不是简单地知道什么是高效的,然后按照惯例去做。在大多数情况下,编写良好的代码和糟糕的代码一样容易。有时候需要更多的工作,那就可以考虑稍后再做。 - Dov
@Dov:我完全同意,如果是在做一些明显劣质的事情和做正确的事情并且可能会更好地执行相同的工作之间进行选择时,做正确的事情并不是过早优化。但是,在许多方面,数组都比列表差,并且直接使用它们几乎肯定会创建更多的工作来完成简单的事情,并使代码更难理解,并且很可能不会传达任何重要的性能改进,除了最低级别的代码外。这就是为什么我认为这是过早优化的原因。 - ColinD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接