RandomAccess接口的使用
RandomAccess在类Collections的shuffle()方法中的使用:(jdk源码如下)
/**
* Randomly permute the specified list using the specified source of
* randomness. All permutations occur with equal likelihood
* assuming that the source of randomness is fair.<p>
*
* This implementation traverses the list backwards, from the last element
* up to the second, repeatedly swapping a randomly selected element into
* the "current position". Elements are randomly selected from the
* portion of the list that runs from the first element to the current
* position, inclusive.<p>
*
* This method runs in linear time. If the specified list does not
* implement the {@link RandomAccess} interface and is large, this
* implementation dumps the specified list into an array before shuffling
* it, and dumps the shuffled array back into the list. This avoids the
* quadratic behavior that would result from shuffling a "sequential
* access" list in place.
*
* @param list the list to be shuffled.
* @param rnd the source of randomness to use to shuffle the list.
* @throws UnsupportedOperationException if the specified list or its
* list-iterator does not support the <tt>set</tt> operation.
*/
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
Object arr[] = list.toArray(); // Shuffle array
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i)); // Dump array back into list
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
类Collections的shuffle()方法
由以上的jdk源码可见,在对实现list接口的对象进行洗牌,打乱时,区分了该类是否是RandomAccess的实例,这样做有什么意义呢?请继续向下看:
在jdk文档中对RandomAccess接口的定义如下:
/**
* Marker interface used by <tt>List</tt> implementations to indicate that
* they support fast (generally constant time) random access. 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.
*
* <p>The best algorithms for manipulating random access lists (such as
* <tt>ArrayList</tt>) can produce quadratic behavior when applied to
* sequential access lists (such as <tt>LinkedList</tt>). Generic list
* algorithms are encouraged to check whether the given list is an
* <tt>instanceof</tt> 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.
*
* <p>It is recognized that the distinction between random and sequential
* access is often fuzzy. For example, some <tt>List</tt> implementations
* provide asymptotically linear access times if they get huge, but constant
* access times in practice. Such a <tt>List</tt> implementation
* should generally implement this interface. As a rule of thumb, a
* <tt>List</tt> implementation should implement this interface if,
* for typical instances of the class, this loop:
* <pre>
* for (int i=0, n=list.size(); i < n; i++)
* list.get(i);
* </pre>
* runs faster than this loop:
* <pre>
* for (Iterator i=list.iterator(); i.hasNext(); )
* i.next();
* </pre>
*
* <p>This interface is a member of the
* <a href="{@docRoot}/../guide/collections/index.html">
* Java Collections Framework</a>.
*
*/
public interface RandomAccess {
}
List 实现所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
将操作随机访问列表的最佳算法(如 ArrayList )应用到连续访问列表(如 LinkedList )时,可产生二次项的行为。如果将某个算法应用到连续访问列表,那么在应用可能提供较差性能的算法前,鼓励使用一般的列表算法检查给定列表是否为此接口的一个 instanceof ,如果需要保证可接受的性能,还可以更改其行为。
现在已经认识到,随机和连续访问之间的区别通常是模糊的。例如,如果列表很大时,某些 List 实现提供渐进的线性访问时间,但实际上是固定的访问时间。这样的 List 实现通常应该实现此接口。
JDK中推荐的是对List集合尽量要实现RandomAccess接口
如果集合类是RandomAccess的实现,则尽量用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历,在效率上要差一些。反过来,如果List是Sequence List,则最好用迭代器来进行迭代。
JDK中说的很清楚,在对List特别是Huge size的List的遍历算法中,要尽量来判断是属于RandomAccess(如ArrayList)还是Sequence List (如LinkedList),因为适合RandomAccess List的遍历算法,用在Sequence List上就差别很大,常用的作法就是:
要作一个判断:
if (list instance of RandomAccess) {
for(int m = 0; m < list.size(); m++){}
}else{
Iterator iter = list.iterator();
while(iter.hasNext()){}
}
package testrandomaccess; import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.RandomAccess; /**
*
* @author bolong
*/
public class TestRandomAccess {
// 初始化列表 public static void initList(List list, int n) {
for (int i = 0; i < n; i++) {
list.add(i);
}
}
//使用循环进行对列表的迭代 public static void traverseWithLoop(List list) {
long starttime = 0;
long endtime = 0;
starttime = System.currentTimeMillis();
for (int count = 0; count <= 1000; count++) {
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
}
endtime = System.currentTimeMillis();
System.out.println("使用loop迭代一共花了" + (endtime - starttime) + "ms时间"); }
//使用迭代器对列表进行迭代 public static void traverseWithIterator(List list) {
long starttime = 0;
long endtime = 0;
starttime = System.currentTimeMillis();
for (int count = 0; count <= 1000; count++) {
for (Iterator itr = list.iterator(); itr.hasNext();) {
itr.next();
}
}
endtime = System.currentTimeMillis();
System.out.println("使用Iterator迭代一共花了" + (endtime - starttime) + "ms时间");
} public static void traverse(List list) { long starttime = 0;
long endtime = 0;
if (list instanceof RandomAccess) {
System.out.println("该list实现了RandomAccess接口");
starttime = System.currentTimeMillis();
for (int count = 0; count <= 1000; count++) {
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
}
endtime = System.currentTimeMillis();
System.out.println("迭代一共花了" + (endtime - starttime) + "ms时间");
} else {
System.out.println("该list未实现RandomAccess接口");
starttime = System.currentTimeMillis();
for (int count = 0; count <= 1000; count++) {
for (Iterator itr = list.iterator(); itr.hasNext();) {
itr.next();
}
}
endtime = System.currentTimeMillis();
System.out.println("迭代一共花了" + (endtime - starttime) + "ms时间");
}
} public static void main(String[] args) {
ArrayList arraylist = new ArrayList();
LinkedList linkedlist = new LinkedList();
initList(arraylist, 1000);
initList(linkedlist, 1000);
traverse(arraylist);
traverse(linkedlist);
traverseWithIterator(arraylist);
traverseWithLoop(arraylist);
traverseWithIterator(linkedlist);
traverseWithLoop(linkedlist);
}
}
验证RandomAccess的代码
根据程序输出的结果的确证明了,arraylist等实现了RandomAccess接口的类在进行迭代时使用loop效率更高,而linkedList那些未实现该接口的类在进行迭代时使用Iterator进行迭代效率更高.
RandomAccess接口的使用的更多相关文章
- Java集合类:"随机访问" 的RandomAccess接口
引出RandomAccess接口 如果我们用Java做开发的话,最常用的容器之一就是List集合了,而List集合中用的较多的就是ArrayList 和 LinkedList 两个类,这两者也常被用来 ...
- Java Collections Framework 之 RandomAccess接口
在研究Collections类的排序算法时候,看到这样的代码 : public static <T> int binarySearch(List<? extends Comparab ...
- ArrayList集合实现RandomAccess接口有何作用?为何LinkedList集合却没实现这接口
详见:https://blog.csdn.net/weixin_39148512/article/details/79234817 众所周知,在List集合中,我们经常会用到ArrayList以及Li ...
- 难倒你了吧!ArrayList 为啥要实现 RandomAccess 接口?
作者:蔡先森_caiyq https://www.jianshu.com/p/3e2a9e4c9e01 在我们的开发中,List接口是最常见不过,而且我们几乎每天都在用ArrayList或者Linke ...
- randomAccess接口
http://www.blogjava.net/lzqdiy/archive/2007/04/22/112578.html
- Java的四个标记接口:Serializable、Cloneable、RandomAccess和Remote接口
一.概述 标记接口是一些没有属性和方法的接口,也是一种设计思想.Java中的一个标记接口表示的的是一种类的特性,实现了该标记接口的类则具有该特性.如实现了Serializable接口的类,表示这个类的 ...
- 关于接口 RandomAccess
今天看到java.util.Collections这个工具类中的 public static <T> void fill(List<? super T> list, T obj ...
- 为什么这些java接口没有抽象方法?浅谈Java标记接口
在jdk的源码中,存在这样的一些接口,他们不包含任何的(抽象)方法,但是却广泛的存在. 这种接口我们称之为Mark Interface,也就是标记接口. 这些接口呢,我们不用来实现任何的方法,他们的作 ...
- Java 之 List<T> 接口的实现:ArrayList
Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHashMap ArrayLis ...
随机推荐
- COGS 144. [USACO Dec07] 魅力手镯【01背包复习】
144. [USACO Dec07] 魅力手镯 ★ 输入文件:charm.in 输出文件:charm.out 简单对比 时间限制:1 s 内存限制:8 MB 译 by CmYkRgB1 ...
- UVA10341-Solve It-二分查找
二分查找 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表.首先,假设表中元素是按升序 ...
- Spring框架学习笔记(6)——bean的继承与依赖
一.bean的继承 Spring通过bean标签的parent属性来实现bean的继承,这个继承的概念只存在于配置层面,也就是说bean只会继承其父bean的属性值. 父bean可以通过abstrac ...
- oracle 11g体系结构
1.数据库体系结构 1.1 数据库和实例的关系database server = instance 实例 + database 数据库instance 实例 =内存 memory + 进程 pr ...
- typedef和define具体的详细区别
1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错.例如: #define PI 3.141 ...
- web框架前言与学生数据库系统(附1.0源码)
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def f1(request): ""&quo ...
- Centos6.7安装mysql 5.6简单教程
今天项目经理让我给服务器配一下mysql,以前配置mysql的时候,感觉好麻烦,前几天也帮朋友配置来着,今天装的时候一直报错,百度也没搞明白,所以打算换种方法装mysql,无意中发现了还有这种操作,容 ...
- Linux终端连接Linux服务器
我们经常需要通过类UNIX下连接我们的Linux服务器.比如我的Mac下经常需要连接上Linux服务器.一般系统都提供了ssh支持,可以直接连接: 通过命令: ssh root@120.25.12.9 ...
- 关于将dede织梦data目录迁移出web目录
关于将dede织梦data目录迁移出web目录织梦官方提供了一个教程,但是如果你是按照他们提供的教程做的话会出现很多问题.比如验证码问题,图片显示问题等等一大堆.织梦官方这种是很不负责任的,因为那个教 ...
- Dedecms列表页标签list/pagelist使用方法及pagelist的样式
Dede的默认页面中有个list_article.htm页面,这是dede的列表页面.在列表页显示文章的列表,是通过dede的list和pagelist这两个个标签实现的.本文就这两个标签的使用及pa ...