【问题标题】:Why does ArrayList implement RandomAccess Interface?ArrayList 为什么要实现 RandomAccess 接口?
【发布时间】:2014-01-01 15:11:05
【问题描述】:

ArrayList 实现RandomAccess 接口。 RandomAccess 接口没有方法。当我检查LinkedList 时,它没有实现RandomAccess 接口。

那么在ArrayList的情况下,实现它有什么意义呢?

【问题讨论】:

  • RandomAccess 接口意味着支持对所选随机索引的元素进行更快的检索访问[通常为常数时间 O(1)]。
  • 虚无地实现RandomAccess接口。*
  • @KanagaveluSugumar:上面分享的知识文章,从数据存储在硬盘中的角度显示了差异,还有s​​eek操作等。然而,在这里,如果我没记错的话,我们正在查看存储在内存中的数据。例如,整个 ArrayList(底层数组),存储在内存中。

标签: java collections


【解决方案1】:

没有方法的接口在 Java 中称为标记接口。

根据 RandomAccess 的 JavaDoc:

List 实现用来指示的标记接口
它们支持快速(通常是恒定时间)随机访问。

有关更多信息,请查看两个 JavaDoc 页面。

http://docs.oracle.com/javase/6/docs/api/java/util/RandomAccess.html

http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html

【讨论】:

  • ArrayList 使用的是顺序数组内存,那为什么叫随机访问呢?我认为 HashMap 是随机访问的好例子,因为数据是分散的,但仍然提供更快的访问 rit ..?
  • 还有为什么没有顺序访问标记接口?是 List 接口表示这种顺序访问吗?
  • @KanagaveluSugumar 在这种情况下,随机访问意味着访问任何元素所花费的时间与访问另一个元素所花费的时间相同。这适用于数组(因此也适用于 ArrayList),因为您可以通过索引访问任何项目。由于数组是按顺序存储在内存中的,因此适用随机存取内存的规则。但是,对于 LinkedList,情况并非如此,因为您始终需要遵循对所需元素的引用。
  • ArrayLists 不需要按顺序访问,即使它们是按顺序存储的,因为索引只是数组在内存中地址的偏移量。
【解决方案2】:

RandomAccess 接口没有方法

这称为标记接口,是一种称为marker interface pattern 的设计模式。

当我检查 LinkedList 时,它没有实现 RandomAccess 接口。那么在 ArrayList 的情况下,实现它的意义何在?

因为在 LinkedList 中的随机访问是 O(n),而在 ArrayList 中是 O(1)。

doc 中有说明:

处理随机访问列表的最佳算法(例如 ArrayList) 在应用于顺序时可以产生二次行为 访问列表(如 LinkedList)

【讨论】:

    【解决方案3】:

    这似乎在文档中得到了很好的描述: http://docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html

    List 使用的 RandomAccess Marker 接口 的实现表明它们支持快速(通常是常量 时间)随机访问。该接口的主要目的是允许 通用算法来改变它们的行为以提供良好的性能 当应用于随机或顺序访问列表时。最好的 用于操作随机访问列表的算法(例如 ArrayList) 应用于顺序访问列表时会产生二次行为 (如链表)。鼓励通用列表算法检查 在应用之前给定的列表是否是这个接口的一个实例 一种算法,如果应用于 顺序访问列表,并在必要时更改其行为 保证可接受的性能。

    众所周知,随机和顺序的区别 访问往往是模糊的。例如,一些 List 实现提供 渐近线性访问时间,如果它们变得巨大但恒定 实际访问时间。这样的 List 实现通常应该 实现这个接口。根据经验,List 实现 应该实现这个接口,如果,对于典型的实例 类,这个循环:

     for (int i=0, n=list.size(); i < n; i++)
         list.get(i);   
    

    比这个循环运行得更快:

     for (Iterator i=list.iterator(); i.hasNext(); )
         i.next();
    

    【讨论】:

      【解决方案4】:

      1) 有两个类实现了RandomAccess 接口。它们是:

      ArrayList (Part of List<I>)
      Vector    (Part of List<I>)
      

      2) RandomAccess 接口的目的是以相同的速度检索集合中的任何随机元素。示例:我有 100 万个对象的集合。实现RandomAccess 接口使您检索第 10 个元素和第 17869 个元素的时间相同。这使得ArrayListVector 更加强大。

      3) RandomAccess 接口没有方法或字段,也称为标记接口。这些用于向编译器指示某些内容,换句话说,实现这些接口意味着对实现类进行一些特殊处理。

      【讨论】:

        【解决方案5】:

        让我们看看如何实际使用这个标记界面。首先是来自docs 的相关部分(粗体是我的,只是为了强调)。

        List使用的Marker接口 实现表明他们支持快速(通常是恒定的 时间)随机访问。该接口的主要目的是允许 通用算法来改变它们的行为以提供良好的性能 当应用于随机或顺序访问列表时。随机访问 List 实现使用的标记接口来指示它们 支持快速(通常是恒定时间)随机访问。首要的 此接口的目的是允许 通用算法 改变 当应用于任一 随机或顺序访问列表。最佳算法 操纵随机访问列表(如 ArrayList)可以产生 应用于顺序访问列表时的二次行为(例如 链表)。

        让我们举个例子。假设您正在编写诸如排序之类的算法的通用实现,并且您正在选择快速排序,因为您想要就地排序。为什么是通用?因为也许您希望算法能够在各种 List 上使用合理且可预测的性能特征(有many 种类 - 没有)。所以你的算法函数会 将列表作为输入并返回与排序相同的列表。暂时让我们抛开影响快速排序性能的各种因素(例如已经排序的数据、重复的数据、正确选择枢轴等)。 除了数据/排序的上述特征之外,另一个关键点是您的算法使我们需要遍历列表 - 在这种情况下,它大量使用随机访问,因为它需要比较和交换 元素。那么你怎么看 - 你的算法会在所有类型的 List 实现上表现良好。想想LinkedList - API 中有随机访问的规定,但它 需要大量遍历,因为数据在列表中组织方式的本质是作为指向彼此的节点以及通过大量节点到达随机节点的痛苦不可避免的行为。因此,您的通用算法在性能方面具有更大的可变性。 如果您以某种方式知道某些列表提供快速随机访问,而有些则不提供。如果有一个这样说的标记怎么办。进来的是由 ArrayList 实现的“RandomAccess”标记接口(标记/注释会更好) 表明(您的代码通常会使用 instanceof RandomAccess 测试检查)随机访问它的数据非常快,您可以依靠它来编写一个执行的算法,如果某些列表没有那么尝试另一种算法,或者先将其转换为 ArrayList,或者在最坏的情况下拒绝这样的输入 完全。

        doc 的另一部分通过提供两种不同的方式来访问易于理解的基础数据来处理被认为是快速随机的内容。快速随机访问意味着第一个总是比第二个运行得快。

        for (int i=0, n=list.size(); i < n; i++)
                 list.get(i);
        
        runs faster than this loop:
             for (Iterator i=list.iterator(); i.hasNext(); )
                 i.next();
        

        【讨论】:

        • 你知道为什么第一个比迭代器运行得快吗?
        【解决方案6】:

        RandomAccess 接口表示对 Collection 元素的高效随机访问

        在客户端代码中,您可以检查集合是否为 RandomAccess 的实例,然后只执行 Random 访问操作。

        可以随机访问 LinkedList 和 ArrayList 中的元素,但 ArrayList 复杂度为 O(1),LinkedList 为 O(n)。

        【讨论】:

          【解决方案7】:

          该接口没有方法(Marker Interface),但你可以用它来测试一个特定的集合是否支持高效的随机访问

          Collection<Integer> c = new ArrayList<Integer>();
          if (c instanceof RandomAccess)
          {
                  System.out.println("use random access algorithm -> like ArrayList");//fast access date
          }
          else
          {
                  System.out.println("use sequential access algorithm -> like LinkedList");//fast delete data 
          }
          

          【讨论】:

            【解决方案8】:
            1. 标记界面的唯一存在是,它表示(或 期望 ) 来自实现类的特定行为。

            2. 因此,在我们的例子中,ArrayList 实现了 RandomAccess 标记接口。

            3. 因此,ArrayList 类的期望是,当客户端想要访问某个索引处的某个元素时,它应该对 ArrayList 类的客户端产生 RandomAccess 行为。

            那么,ArrayList 是如何实现这种随机性的呢?

            public E get(int index) {
                    rangeCheck(index); // to check for out of bounds index.
            
                    return elementData(index); // another method invocation
                }
            
            E elementData(int index) {
                    return (E) elementData[index]; // accesses internal array.
                }
            
            // following is the internal array , used by ArrayList
            transient Object[] elementData; // non-private to simplify nested class access
            
            1. 现在,我们知道 LinkedList 并没有实现 RandomAccess,因此,它不能保证随机访问行为。让我们也检查一下下面的 LinkedList 代码,注意这里的 for 循环,所以,它是一个顺序访问。还要注意按位运算符的技巧:size &gt;&gt; 1 表示大小除以 2。因此,它基本上检查索引是在前半部分还是后半部分。如果是在下半场,从头开始是有意义的。这是一个优化,好技巧。

              `public E get(int index) { checkElementIndex(索引); 返回节点(索引).item; }

              节点节点(int index){ // 断言 isElementIndex(index);

               if (index < (size >> 1)) {
                   Node<E> x = first;
                   for (int i = 0; i < index; i++)
                       x = x.next;
                   return x;
               } else {
                   Node<E> x = last;
                   for (int i = size - 1; i > index; i--)
                       x = x.prev;
                   return x;
               }
              

              }`

            【讨论】:

              【解决方案9】:

              RandomAccess : 这个接口是在 Java 1.4 版本中引入的。它标记了可以随机访问的列表的实现。它存在于 java.util.RandomAccess

              List 实现使用的标记接口表明它们支持快速随机访问。

              更准确地说,RandomAccess 接口识别使用 List.get() 方法迭代更快的 List 实现而不是使用 Iterator.next() 方法。

              ArrayList 实现了 RandomAccess 接口。 RandomAccess 接口没有方法。当我检查 LinkedList 时,它没有实现 RandomAccess 接口。

              因为 ArrayList 和 Vector 是基于索引的,而 LinkedList 遵循双链表。

              时间复杂度

              数组列表: Java 中的 ArrayList 由数组支持。 随机访问需要 O(1) 时间

              get() – 总是一个常数时间 O(1) 操作

              链表 LinkedList 是一种线性数据结构,由持有数据字段的节点和对另一个节点的引用组成。

              get() - 搜索一个元素需要 O(n) 时间。

              注意: ArrayList 可以为您提供 O(1) 复杂度的任何元素,因为该数组具有随机访问属性。您可以直接访问任何索引,而无需遍历整个数组。

              LinkedList 具有顺序访问属性。它需要遍历每个元素以达到给定的索引,因此从 LinkedList 中按索引获取值的时间复杂度是 O(N)。

              【讨论】:

                【解决方案10】:

                RandomAccess:标记接口

                java.util.RandomAccess - 从 JDK 1.4 开始,集合框架的成员。 实现:ArrayList 和 CopyOnWriteArrayList。

                用于数据的随机访问(基于索引)

                List 实现使用的标记接口表明它们支持快速(通常是恒定时间)随机访问。此接口的主要目的是允许通用算法改变其行为,以便在应用于随机或顺序访问列表时提供良好的性能。

                用于操作随机访问列表(例如 ArrayList)的最佳算法在应用于顺序访问列表(例如 LinkedList)时会产生二次行为。

                鼓励通用列表算法在应用算法之前检查给定列表是否是此接口的实例,如果将其应用于顺序访问列表会提供较差的性能,并在必要时更改其行为以保证可接受的性能。

                众所周知,随机访问和顺序访问之间的区别通常很模糊。

                List 实现应该实现这个接口,如果,对于典型的类实例,这个循环:

                for (int i=0, n=list.size(); i < n; i++)
                         list.get(i);
                
                runs faster than this loop:
                
                for (Iterator i=list.iterator(); i.hasNext(); )
                         i.next();
                

                更多信息请看我的博客:
                http://javaexplorer03.blogspot.in/2015/07/randomaccess-java.html

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-07-05
                  • 2022-07-25
                  • 2013-05-01
                  • 2011-02-12
                  • 2011-05-05
                  • 2010-09-29
                  相关资源
                  最近更新 更多