为什么ArrayList实现RandomAccess接口?

时间:2014-01-01 15:11:05

标签: java collections

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

因此,在ArrayList的情况下,实施它的重点是什么?

10 个答案:

答案 0 :(得分:26)

没有方法的接口在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

答案 1 :(得分:13)

  

RandomAccess接口没有方法

这称为标记界面,是一种名为marker interface pattern的设计模式。

  

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

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

doc

中说明了这一点
  

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

答案 2 :(得分:3)

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

  

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

     

认识到随机和顺序之间的区别   访问通常是模糊的。例如,一些List实现提供   渐近线性访问时间,如果它们变大,但不变   在实践中访问时间。一般来说,这样的列表实施   实现这个接口。根据经验,一个List实现   对于典型的实例,应该实现此接口   class,这个循环:

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

比这个循环运行得更快:

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

答案 3 :(得分:1)

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

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

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

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

答案 4 :(得分:1)

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

  

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

让我们举个例子。假设您正在编写排序等算法的通用实现,并且您正在选择快速排序,就像您想要就地排序一样。为什么泛型?因为您可能希望算法能够在各种List上使用合理且可预测的性能特征(其中有many种类型 - 不是&n; t)。所以你的算法函数会 将列表作为输入并返回与已排序相同的列表。暂时不要考虑影响快速排序性能的各种因素(例如已排序的数据,重复的数据,正确选择枢轴等)。 除了数据/排序的上述特征之外,另一个关键点是你的算法让我们厌倦了遍历列表 - 在这种情况下,它会大量使用随机访问,因为它需要比较和交换 元素。那么你怎么看 - 你的算法在所有类型的List实现上都能表现得很好。考虑LinkedList - API中有随机访问的规定 需要大量的遍历,因为数据在列表中的组织方式本质上是指向彼此的节点以及通过大量节点到达随机节点的痛苦不可避免的行为。因此,您的通用算法在性能方面具有更多可变性。 如果你知道某些列表提供快速的ramdom访问而有些列表没有,那会怎么样?如果有一个标记,那该怎么办?来自&#34; RandomAccess&#34;由ArrayList实现的标记接口(标记/注释将是更好的单词) 表示(您的代码通常会检查 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();

答案 5 :(得分:0)

RandomAccess:标记界面

java.util.RandomAccess - 自JDK 1.4以来,收集框架的成员。 Implemetations:ArrayList和CopyOnWriteArrayList。

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

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

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

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

人们认识到随机访问和顺序访问之间的区别通常是模糊的。

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

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

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

该接口没有方法(标记接口),但是您可以使用它来测试特定集合是否支持有效的随机访问

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 :(得分:0)

  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 >> 1的意思是,大小除以2。因此,它基本上检查索引是在上半部还是后半部。如果在下半场,则从结尾开始是有意义的。这是一个优化,很好的技巧。

    `public E get(int index){ checkElementIndex(index); 返回node(index).item; }

    节点node(int索引){ //断言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 :(得分:0)

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

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

更准确地说,RandomAccess接口可以识别 List实现,这些实现使用List.get()方法而不是使用 Iterator.next()方法进行迭代。

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

因为ArrayList和Vector是基于索引的,而LinkedList是在双链表之后。

时间复杂度

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

get()–始终是恒定时间O(1)操作

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

get()–搜索元素需要O(n)时间。

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

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