CodeGym /Java 博客 /随机的 /图片中的ArrayList
John Squirrels
第 41 级
San Francisco

图片中的ArrayList

已在 随机的 群组中发布
你好!今天的课程ArrayList将比以前的课程更容易也更难。
图片中的 ArrayList - 1
这将更加困难,因为今天我们将深入了解ArrayList并研究各种操作期间发生的情况。另一方面,本课几乎没有代码。主要是图片和解释。好吧,让我们开始:) 如您所知,ArrayList内部有一个普通数组,用作数据存储。在大多数情况下,我们不指定列表的确切大小。但是内部数组必须有一定的大小!确实如此。它的默认大小是 10

public static void main(String[] args) {
   ArrayList<Car> cars = new ArrayList<>();
}
图片中的 ArrayList - 2 首先,让我们看看添加新元素是什么样子的。第一项业务是检查内部数组是否有足够的空间在内部数组中以及是否可以容纳更多元素。如果有空间,则将新元素添加到列表的末尾。当我们说“到最后”时,我们并不是指数组中的最后一个位置(那会很奇怪)。我们指的是最后一个当前元素之后的位置。它的索引将是cars.size()。我们的列表目前为空 ( cars.size() == 0)。因此,新元素将添加到位置 0。

ArrayList<Car> cars = new ArrayList<>();
Car ferrari = new Car("Ferrari 360 Spider");
cars.add(ferrari);
图片中的 ArrayList - 3 这很清楚。如果我们插入中间,即在其他元素之间会发生什么?

public static void main(String[] args) {
   ArrayList<Car> cars = new ArrayList<>();
   Car ferrari = new Car("Ferrari 360 Spider");
   Car bugatti = new Car("Bugatti Veyron");
   Car lambo = new Car("Lamborghini Diablo");
   Car ford = new Car("Ford Modneo");
  
   cars.add(ferrari);
   cars.add(bugatti);
   cars.add(lambo);
  
   cars.add(1, ford);// add ford to cell 1, which is already occupied
}
同样,首先检查数组中是否有足够的空间。如果有足够的空间,则元素向右移动,从我们插入新元素的位置开始。我们在位置 1 插入。换句话说,位置 3 的元素被复制到位置 4,元素 2 复制到位置 3,元素 1 复制到位置 2。 图片中的 ArrayList - 4 然后我们的新元素被插入到它的位置。先前的元素 (bugatti) 已从那里复制到新位置。 图片中的 ArrayList - 5 现在让我们看看如果没有地方可以向数组中插入新元素,这个过程是如何发生的。 图片中的 ArrayList - 6 当然,首先要检查是否有足够的空间。如果没有足够的空间,则在内部创建一个新数组ArrayList其大小是旧数组的大小乘以 1.5 加 1 在我们的例子中,新数组的大小将为 16。所有当前元素将被立即复制到那里。 图片中的 ArrayList - 7 旧数组将被垃圾收集器删除,只有新的扩展数组会保留下来。现在有一个新元素的空间。我们将它插入位置 3,该位置已被占用。现在熟悉的程序开始了。从索引 3 开始的所有元素都向右移动一位,然后新元素悄悄添加。 图片中的 ArrayList - 8 插入完成!我们完成了插入。现在让我们谈谈删除项目。你会记得我们在处理数组时遇到了一个问题:删除元素会在数组中产生“洞”。每次删除,我们每次都必须编写自己的代码来执行此转换。 ArrayList 遵循相同的原则,但它已经实现了这种机制。 图片中的 ArrayList - 9 它看起来是这样的: 图片中的 ArrayList - 10 最后我们得到了我们想要的: 图片中的 ArrayList - 11lambo元素已被删除。这里我们从中间移除了一个元素。显然,从列表末尾删除一个元素更快,因为该元素被简单地删除而不需要移动所有其他元素。让我们再讨论一下内部数组的维度以及它在内存中的排列方式。 扩展数组需要一些资源。 因此,不要创建ArrayList如果您确定它至少有 100 个元素,则使用默认大小。当您插入第 100 个元素时,内部数组必须扩展6 倍,并且每次都必须移动所有元素。
  • 从 10 个元素到 16 个
  • 从 16 个元素到 25 个
  • 从 25 到 38
  • 从 38 到 58
  • 从 58 到 88
  • 从 88 到 133(即旧数组的大小乘以 1.5 加 1)
可以想象,这是相当耗费资源的。 因此,如果您已经知道(甚至大约)所需的项目数量,最好创建一个包含特定大小数组的列表:

ArrayList<Car> cars = new ArrayList<>(100);
现在,包含 100 个元素的数组的内存将一次性全部分配,从而使数组更有效率(不需要扩展)。这种策略也有不利的一面。 当您从 中删除对象时ArrayList,内部数组的大小不会自动减小。 假设我们有一个ArrayList包含 88 个元素的完全完整的内部数组: 图片中的 ArrayList - 12 在程序运行时,我们删除了 77 个元素,因此只剩下 11 个: 图片中的 ArrayList - 13 你已经猜到问题是什么了吗?你明白了,内存使用效率低下!我们在这里只使用了 11 个位置,但我们已经为 88 个元素分配了内存。这比我们需要的多 8 倍!在这种情况下,我们可以使用该类的一种ArrayList特殊方法来优化我们的内存使用:trimToSize(). 此方法将内部数组的长度“修剪”为当前存储在其中的元素数。 图片中的 ArrayList - 14 现在我们只分配了我们需要的内存!:)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION