JavaRush /Java 博客 /Random-ZH /Java中的ArrayList图片

Java中的ArrayList图片

已在 Random-ZH 群组中发布
你好!今天的讲座ArrayList,一方面比之前的讲座更简单,另一方面也比之前的讲座更难。 图片中的 ArrayList 工作 - 1这更加困难,因为今天我们将深入了解“幕后”ArrayList并研究它在操作过程中会发生什么。另一方面,本次讲座中几乎没有代码——主要是图片和解释。那么,我们开始吧:) 正如您所知,ArrayList'a 内部有一个普通数组,充当数据存储。在大多数情况下,我们不指定列表的确切大小。但内部数组必须有一定的大小!这是真实的。它的默认大小是 [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);//добавляем ford в ячейку 1, которая уже занята
}
同样,它首先检查数组中是否有足够的空间。如果有足够的空间,元素将从我们插入新元素的单元格开始向右移动。我们粘贴到索引为 1 的单元格中。也就是说,单元格 3 中的元素被复制到单元格 4 中,元素 2 被复制到单元格 3 中,元素 1 被复制到单元格 2 中。 在图片中使用 ArrayList - 4之后,我们的新元素被粘贴到位。前一个元素 ( bugatti) 已从此处复制到新位置。 在图片中使用 ArrayList - 5现在让我们弄清楚如果数组中没有空间可插入,这个过程将如何发生。 在图片中使用 ArrayList - 6当然,首先要检查是否有足够的空间。如果发现空间不足,ArrayList则会在 'a 内创建一个大小为 (OldArray 的大小 * 1.5) + 1 的新数组。在我们的例子中,新数组的大小为 16 个单元格。所有当前元素将立即复制到那里。 在图片中使用 ArrayList - 7旧的数组将被垃圾收集器删除,只保留新的、扩展的数组。现在有新元素的可用空间。我们将其粘贴到已被占用的单元格 3 中。现在熟悉的程序开始了。从索引 3 开始的所有元素都向右移动一个单元格,并悄悄添加一个新元素。 在图片中使用 ArrayList - 8现在插入成功了!我们整理了插入。现在我们来谈谈删除元素。正如您所记得的,在使用数组时,我们遇到了一个问题:当我们删除它们时,“洞”仍然存在于其中。唯一的解决方案是每次删除元素时 将元素向左移动,并且您必须自己编写移动代码。ArrayList工作原理相同,但在其中该机制已经自动实现。 在图片中使用 ArrayList - 9看起来是这样的: 在图片中使用 ArrayList - 10最后我们得到了想要的结果: 在图片中使用 ArrayList - 11元素lambo被成功删除。这里我们从中间进行了删除。显然,从列表末尾删除会更快,因为删除所需元素时不会移动所有其他元素。我们再看一下内部数组的大小以及它在内存中的存储情况。 数组扩展是一个需要消耗一定资源的过程。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 - 13在程序运行过程中,我们从中删除了 77 个元素,只剩下 11 个元素: 在图片中使用 ArrayList - 14你已经猜到问题是什么了吗?当然,内存使用效率低下!我们只使用 11 个单元,而我们为 88 个元素分配了内存 - 这比我们需要的多 8 倍!要在这种情况下进行优化,可以使用特殊的类方法ArrayList- trimToSize()。它将内部数组的长度“剪切”为当前存储在其中的元素数量。 在图片中使用 ArrayList - 15现在已根据需要分配了尽可能多的内存!:)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION