【问题标题】:How does LinkedList work internally in Java?Java 内部的 LinkedList 是如何工作的?
【发布时间】:2011-11-23 08:47:53
【问题描述】:

据我所知,链表的概念是通过具有“下一个”,有时是“上一个”属性来遍历对象而相互连接的一堆对象。

我注意到在 Java 中,您可以创建一个 LinkedList 对象...但是通过使用 .add()、.get() 等相同的方法将其视为数组/列表/序列。

那么,LinkedList 内部是不是类似数组的序列?

【问题讨论】:

标签: java linked-list


【解决方案1】:

那么,LinkedList 内部是不是类似数组的序列?

没有。它是私有嵌套类Entry 的一系列实例,它具有nextpreviouselement 引用。请注意,您可以通过查看 JDK 附带的源代码自己发现这一点。

这个内部结构不暴露的原因是它可以防止结构被破坏,例如包含一个循环。通过ListDeque 接口的统一访问允许多态使用。

【讨论】:

  • +1:内部是类似数组的序列的列表称为ArrayList。 ;)
  • -1:我猜这取决于你的编程技巧。来自关于链接列表的维基百科文章:“它也可能很慢,并且使用幼稚的分配器,很浪费,为每个新元素单独分配内存,通常使用内存池解决问题。” -- 仅供参考,内存池是专业人士用来在内部存储链表的数组。它们也被称为平板分配器。
  • @Anthony: 报复投反对票,嗯?克服它。熟练的专业人士不会在互联网上拉扯问题应该回答的级别。
  • @MichaelBorgwardt 绝对不是。我同意您对“否”的回答在大多数应用程序和实现中都是正确的,但并非全部。实际上,您可以使用数组作为基础数据结构来实现链表,以防性能受到关注——正如维基百科文章所说。
  • @Anthony Blake 问题是关于Java Collection API 提供的LinkedList 类的特定 实现。一个基于数组的实现是 ArrayList,正如 Peter 之前在他的评论中所说的那样。
【解决方案2】:

Java 中的 LinkedList 的工作方式与您期望的一样。如果您使用官方集合LinkedList,那么它确实是一个通过“下一个”有时是“上一个”相互连接的对象

是的,它有一个 get(int index) 方法,这很令人惊讶,因为它效率不高,因为您需要从头开始并在列表中向上计数才能找到 indexth 条目,这是不是 LinkedLists 擅长的。之所以存在,是因为 LinkedList 实现了List 接口。这是所有列表都可以做到的。

但是,当您通过 get(int index) 方法访问 LinkedList 时,您可能会尽量避免使用它,因为这显然是最低效的。使用ArrayList 可能会更好。

【讨论】:

    【解决方案3】:

    LinkedList 是一个实体链,其中每个实体都知道下一个实体, 所以 get(index) 操作需要用计数器迭代这个链。 但是这个列表针对按位置添加和删除进行了优化(以防我需要将元素放入列表或从中间链表中删除元素时效果更好)

    【讨论】:

      【解决方案4】:

      据我所知,链表就像您在第一段中所说的那样。每个对象都有两个引用,称为它的上一个和它的下一个。 与按顺序工作的数组不同(在 C 中它完全按顺序存储。我认为 java 也是如此,这就是我们不能重新调整数组大小的原因),列表通过引用工作。所以从逻辑上讲,它的工作速度比数组慢。

      【讨论】:

        【解决方案5】:

        使用链表可以实现像数组一样工作的对象。与数组相比,有些操作会更快,有些操作会更慢。例如,为接近末尾的元素调用get() 可能比使用数组慢得多。不过,还是可以的。

        另一方面,从链表中间删除一个元素将比使用数组完成的相应操作更快。

        【讨论】:

          【解决方案6】:

          不是真的。链表由集合提供,通过良好的设计,您可以创建一个双链表。现在它不像数组,因为这些对象没有索引,也不是容器内的元素,即列表。因此,您需要定义下一个和上一个,并决定下一步是什么。它们都有相同的方法,因为它们又是我所说的集合。

          【讨论】:

            【解决方案7】:

            那么,LinkedList 内部是不是类似数组的序列?

            NO是双向链表实现。

            【讨论】:

              【解决方案8】:

              在内部,它将使用所谓的“slab 分配器”——这基本上是一个小数组的链表。每次添加对象时,它都会检查平板中是否有空间,如果有,则将对象放在那里。否则,它分配一个新的slab并将对象放在slab的第一个元素中。

              这种技术最大限度地减少了内存分配开销——如果你将很多项目添加到一个链表中,那将是大量的小内存分配,需要很多时间,而平板分配器可以最大限度地减少这一点

              【讨论】:

              • 这是完全错误的。 Java 不是 C++。小分配很快。因此,API 实现不会使用任何技巧来避免它。
              • @MichaelBorgwardt 您认为 JVM 从哪里获取它分配的每个对象的内存?你认为 JVM 每次都在调用 malloc() 吗?垃圾收集器使用平板中的内存。请解释您认为 Java 是如何为没有内存块的链表分配内存的。
              • @MichaelBorgwardt 来自有关 IBM JVM 的文档:“这些部分通常实现为受 Java 内存管理器(包括垃圾收集器)控制的本机内存的连续片。”
              • @Anthony Blake 那么为什么不深入解释一下 malloc() 的工作原理呢?您使用什么 JVM 实现作为参考?也存在 8 KiB JVM。这些实现非常简单。您在这里回答问题的步骤太深了。你说得对,知道一些事情在最常见的 JVM 上是如何工作的很好,但是对于像这里这样的问题并不感兴趣。
              • 事实上,这与 Java 中链表的实现无关。 JVM 内部不是问题的一部分。
              猜你喜欢
              • 2017-05-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-09-30
              • 2015-03-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多