简体   繁体   English

为什么 ArrayList 实现了 RandomAccess 接口?

[英]Why does ArrayList implement RandomAccess Interface?

ArrayList implements RandomAccess interface. ArrayList实现了RandomAccess接口。 RandomAccess interface has no methods. RandomAccess接口没有方法。 When I checked LinkedList it does not implement RandomAccess interface.当我检查LinkedList它没有实现RandomAccess接口。

So in case of ArrayList , what is the point of implementing it?那么在ArrayList情况下,实现它的重点是什么?

Interfaces with no methods are called marker interfaces in Java.没有方法的接口在 Java 中称为标记接口。

As per the JavaDoc of RandomAccess:根据 RandomAccess 的 JavaDoc:

Marker interface used by List implementations to indicate List 实现使用的标记接口来指示
that they support fast (generally constant time) random access.它们支持快速(通常是恒定时间)随机访问。

For more information check the two JavaDoc pages.有关更多信息,请查看两个 JavaDoc 页面。

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

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

RandomAccess interface has no method RandomAccess 接口没有方法

This is called a marker interface and is a design pattern called marker interface pattern .这称为标记界面,是一种称为标记界面模式的设计模式

When I checked LinkedList it does not implement RandomAccess interface.当我检查 LinkedList 时,它没有实现 RandomAccess 接口。 So in case of ArrayList what is the point of implementing it?那么在 ArrayList 的情况下,实现它的重点是什么?

Because random access in a LinkedList is O(n), while it's O(1) in an ArrayList .因为LinkedList随机访问是 O(n),而在ArrayList它是 O(1)。

It's stated in the doc :它在文档中说明

The best algorithms for manipulating random access lists (such as ArrayList) can produce quadratic behavior when applied to sequential access lists (such as LinkedList)用于操作随机访问列表(如 ArrayList)的最佳算法在应用于顺序访问列表(如 LinkedList)时可以产生二次行为

This seems pretty well described in the documentation: http://docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html这似乎在文档中得到了很好的描述: http : //docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html

RandomAccess Marker interface used by List implementations to indicate that they support fast (generally constant time) random access . List 实现使用的 RandomAccess Marker 接口来指示它们支持快速(通常是恒定时间)随机访问 The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.此接口的主要目的是允许通用算法改变其行为,以在应用于随机或顺序访问列表时提供良好的性能。 The best algorithms for manipulating random access lists (such as ArrayList) can produce quadratic behavior when applied to sequential access lists (such as LinkedList).用于操作随机访问列表(例如 ArrayList)的最佳算法在应用于顺序访问列表(例如 LinkedList)时可以产生二次行为。 Generic list algorithms are encouraged to check whether the given list is an instanceof this interface before applying an algorithm that would provide poor performance if it were applied to a sequential access list, and to alter their behavior if necessary to guarantee acceptable performance.鼓励通用列表算法在应用算法之前检查给定列表是否是此接口的实例,如果将其应用于顺序访问列表,则会提供较差的性能,并在必要时更改它们的行为以保证可接受的性能。

It is recognized that the distinction between random and sequential access is often fuzzy.人们认识到随机访问和顺序访问之间的区别通常是模糊的。 For example, some List implementations provide asymptotically linear access times if they get huge, but constant access times in practice.例如,一些 List 实现提供了渐近线性的访问时间,如果它们变得巨大,但实际上访问时间是恒定的。 Such a List implementation should generally implement this interface.这样的 List 实现一般应该实现这个接口。 As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:根据经验,如果对于类的典型实例,这个循环,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();

1) There are two classes which implement RandomAccess Interface. 1) 有两个类实现了RandomAccess接口。 They are:他们是:

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

2) The purpose of RandomAccess Interface is to retrieve any random element in the Collection at the same speed. 2) RandomAccess接口的目的是以相同的速度检索集合中的任何随机元素。 Example: I have a collection of 1 million objects.示例:我有 100 万个对象的集合。 Implementing RandomAccess interface makes your time to retrieve the 10th element and 17869th element the same.实现RandomAccess接口使您检索第 10 个元素和第 17869 个元素的时间相同。 This makes ArrayList and Vector more powerful.这使得ArrayListVector更加强大。

3) RandomAccess Interface has no methods or fields and is also called a Marker Interface. 3) RandomAccess接口没有方法或字段,也称为标记接口。 These are used to indicate something to the compiler, in other words implementing these interfaces is meant to imply some special treatment of the implementing class.这些用于向编译器指示某些内容,换句话说,实现这些接口意味着对实现类进行一些特殊处理。

Let's see how you can practically make use of this marker interface.让我们看看如何实际使用这个标记界面。 First the relevant parts from docs (bolds are mine just to emphasise).首先是文档中的相关部分(粗体是我的,只是为了强调)。

Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. List 实现使用的标记接口来指示它们支持快速(通常是恒定时间)随机访问。 The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.此接口的主要目的是允许通用算法改变其行为,以在应用于随机或顺序访问列表时提供良好的性能。 RandomAccess Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. List 实现使用的 RandomAccess Marker 接口来指示它们支持快速(通常是恒定时间)随机访问。 The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.此接口的主要目的是允许通用算法改变其行为,以在应用于随机或顺序访问列表时提供良好的性能 The best algorithms for manipulating random access lists (such as ArrayList) can produce quadratic behavior when applied to sequential access lists (such as LinkedList).用于操作随机访问列表(例如 ArrayList)的最佳算法在应用于顺序访问列表(例如 LinkedList)时可以产生二次行为。

Let's take an example.让我们举个例子。 Suppose you are writing a generic implementation of algorithm such as sort and you are choosing quick sort as you want in-place sorting.假设您正在编写诸如排序之类的算法的通用实现,并且您正在根据需要就地排序选择快速排序。 Why generic ?为什么是泛型 Because maybe you want the algorithm to be able to work with reasonable and predictable performance characteristics on all kinds of List (there are many kinds out there - aren't).因为也许你想要的算法,能够对各种名单的合理性和可预测的性能特性的工作(有许多种在那里-不)。 So your algorithm function would take a list as input and return the same list as sorted.所以你的算法函数会将一个列表作为输入并返回与排序相同的列表。 For a moment let's leave aside the various factors which influence the performance of quick sort (such as already sorted data, repeated data, right choice of pivot etc.).暂时先抛开影响快速排序性能的各种因素(例如已排序的数据、重复的数据、正确选择枢轴等)。 Apart from the above characteristics of the data/sort another crucial point is that your algorithm makes heavy us of traversing the list - in this case it makes use of random access heavily as it needs to compare and swap elements.除了数据/排序的上述特征之外,另一个关键点是您的算法使我们大量遍历列表 - 在这种情况下,它大量使用随机访问,因为它需要比较和交换元素。 So what do you think - will your algorithm perform well on all types of List implementations.那么你怎么看 - 你的算法会在所有类型的 List 实现上表现良好。 Think about LinkedList - there is a provision for random access in the API but it needs lots of traversals because of the very nature of how data is organised in list as nodes pointing to each other and the painful unavoidable act of going through large number of nodes to arrive at a random node.想想LinkedList - API 中有随机访问的规定,但它需要大量的遍历,因为数据在列表中的组织方式的本质是节点相互指向,以及通过大量节点的痛苦不可避免的行为到达随机节点。 So your generic algorithm has more variability in terms of performance.因此,您的通用算法在性能方面具有更大的可变性。 What if you knew somehow that some Lists provide fast ramdom access and some do not.如果您以某种方式知道某些列表提供快速随机存取,而有些则不能。 What if have a marker which says so.如果有一个这样的标记怎么办。 In comes the "RandomAccess" marker interface which is implemented (marked/annotated would be better word) by ArrayList to indicate (your code will typically check with instanceof RandomAccess test) that it's quite fast to access randomly it's data and you can rely on that to write an algorithm which performs and if some list does not then try an alternate algorithm or maybe convert it first into ArrayList or at worst reject such an input entirely. ArrayList 实现了“RandomAccess”标记接口(标记/注释是更好的词),以指示(您的代码通常会使用instanceof RandomAccess 测试进行检查)随机访问它的数据非常快,您可以依赖它编写一个执行的算法,如果某个列表不执行,则尝试替代算法,或者可能首先将其转换为 ArrayList,或者最坏的情况是完全拒绝这样的输入。

Another part of doc deals with what is considered to be fast random by giving two different ways to access the underlying data which is easy to understand.文档的另一部分通过提供两种不同的方式来访问易于理解的基础数据来处理被认为是快速随机的内容。 Fast random access means the first runs faster than second at all times.快速随机访问意味着第一个总是比第二个运行得快。

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();

RandomAccess: Marker interface RandomAccess:标记接口

java.util.RandomAccess - Since JDK 1.4, member of collection framework. java.util.RandomAccess - 从 JDK 1.4 开始,集合框架的成员。 Implemetations: ArrayList and CopyOnWriteArrayList.实现:ArrayList 和 CopyOnWriteArrayList。

For Random access of data (Index basis)对于数据的随机访问(索引基础)

Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. List 实现使用的标记接口来指示它们支持快速(通常是恒定时间)随机访问。 The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.此接口的主要目的是允许通用算法改变其行为,以在应用于随机或顺序访问列表时提供良好的性能。

The best algorithms for manipulating random access lists (such as ArrayList) can produce quadratic behavior when applied to sequential access lists (such as LinkedList).用于操作随机访问列表(例如 ArrayList)的最佳算法在应用于顺序访问列表(例如 LinkedList)时可以产生二次行为。

Generic list algorithms are encouraged to check whether the given list is an instanceof this interface before applying an algorithm that would provide poor performance if it were applied to a sequential access list, and to alter their behavior if necessary to guarantee acceptable performance.鼓励通用列表算法在应用算法之前检查给定列表是否是此接口的实例,如果将其应用于顺序访问列表,则会提供较差的性能,并在必要时更改它们的行为以保证可接受的性能。

It is recognized that the distinction between random and sequential access is often fuzzy.人们认识到随机访问和顺序访问之间的区别通常是模糊的。

A List implementation should implement this interface if, for typical instances of the class, this loop:如果对于类的典型实例,此循环,则 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();

For more information, see my blog:有关更多信息,请参阅我的博客:
http://javaexplorer03.blogspot.in/2015/07/randomaccess-java.html http://javaexplorer03.blogspot.in/2015/07/randomaccess-java.html

RandomAccess interface signifies an Efficient Random access to elements of Collection. RandomAccess 接口表示对 Collection 元素的高效随机访问

In client code, you can check whether the collection is instance of RandomAccess and then only perform the Random access operations.在客户端代码中,您可以检查集合是否是 RandomAccess 的实例,然后只执行 Random 访问操作。

Elements from both LinkedList and ArrayList can be accessed randomly however ArrayList complexity is O(1) and LinkedList is O(n). LinkedList 和 ArrayList 中的元素都可以随机访问,但是 ArrayList 复杂度为 O(1),LinkedList 为 O(n)。

The interface has no methods(Marker Interface), but you can use it to test whether a particular collection supports efficient random access接口没有方法(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 
}
  1. The mere presence of marker interface is that, it indicates ( or expects ) specific behavior from the implementing class.标记接口的存在仅仅是它指示(或期望)来自实现类的特定行为。

  2. So, in our case, ArrayList implements RandomAccess marker interface.所以,在我们的例子中,ArrayList 实现了 RandomAccess 标记接口。

  3. So, the expectation from ArrayList class, is that, it should produce RandomAccess behavior to the clients of ArrayList class, when the client wants to access some element at some index.因此,ArrayList 类的期望是,当客户端想要访问某个索引处的某个元素时,它应该对 ArrayList 类的客户端产生 RandomAccess 行为。

So, how has ArrayList implemented this randomness ?那么,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. Now, we know that LinkedList has not implemented RandomAccess, so , it is not expected to guarantee random access behavior.现在,我们知道 LinkedList 没有实现 RandomAccess,因此,它不能保证随机访问行为。 Let us also check LinkedList code below, Notice the for loop here, so, it is a sequential access.让我们也检查下面的 LinkedList 代码,注意这里的 for 循环,所以,它是一个顺序访问。 And also observe the bitwise operator trick: size >> 1 means that, size is divided by 2. So, it basically checks , if the index is in first half or second half.还要观察按位运算符技巧: size >> 1表示,size 除以 2。因此,它基本上会检查索引是在前半部分还是后半部分。 If it is in second half, it makes sense to start from the end.如果是在下半场,从结尾开始是有道理的。 It is an optimization, good trick.这是一个优化,很好的技巧。

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

    Node node(int index) { // assert isElementIndex(index);节点 node(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; }

    }` }`

RandomAccess : This interface introduced in Java version 1.4. RandomAccess :此接口在 Java 1.4 版中引入。 It marks the implementations of list which can be accessed randomly.它标志着可以随机访问的列表的实现。 It is present in java.util.RandomAccess它存在于java.util.RandomAccess 中

Marker interface used by List implementations to indicate that they support fast random access. List 实现使用的标记接口来指示它们支持快速随机访问。

More accurately, the RandomAccess interface identifies List implementations which are faster to iterate using the List.get() method rather than using the Iterator.next() method.更准确地说,RandomAccess 接口识别使用 List.get() 方法而不是使用Iterator.next() 方法迭代速度更快的 List 实现

ArrayList implements RandomAccess interface. ArrayList 实现了 RandomAccess 接口。 RandomAccess interface has no methods. RandomAccess 接口没有方法。 When I checked LinkedList it does not implement RandomAccess interface.当我检查 LinkedList 时,它没有实现 RandomAccess 接口。

Because ArrayList & Vector are index based & LinkedList is follows Double Linked List.因为 ArrayList 和 Vector 是基于索引的,LinkedList 遵循双链表。

Time Complexity时间复杂度

ArrayList: The ArrayList in Java is backed by an array. ArrayList: Java 中的 ArrayList 由一个数组支持。 Random access takes O(1) time随机访问需要 O(1) 时间

get() – is always a constant time O(1) operation get() – 总是一个常数时间 O(1) 操作

LinkedList LinkedList is a linear data structure which consists of nodes holding a data field and a reference to another node. LinkedList LinkedList 是一种线性数据结构,它由保存数据字段的节点和对另一个节点的引用组成。

get() – searching for an element takes O(n) time. get() – 搜索元素需要 O(n) 时间。

Note: ArrayList can give you any element in O(1) complexity as the array has random access property.注意: ArrayList 可以为您提供 O(1) 复杂度的任何元素,因为数组具有随机访问属性。 You can access any index directly without iterating through the whole array.您可以直接访问任何索引,而无需遍历整个数组。

LinkedList has a sequential access property. LinkedList 具有顺序访问属性。 It needs to iterate through each element to reach a given index, so time complexity to get a value by index from LinkedList is O(N).它需要遍历每个元素才能到达给定的索引,因此从 LinkedList 按索引获取值的时间复杂度为 O(N)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM