1.ArrayList实现RandomAccess接口有什么意义?

发布于 2022年 01月 10日 21:44

RandomAccess标识可以标识随机访问,也就是该集合底层是数组实现,遍历的时候用的应该是for循环,走数组下标访问元素,而不是迭代器

可能上面的表述有点歧义,这么说吧,RandomAccess标识,则说明该集合底层实现是数组,所以,你使用该集合的时候,最底层应该走的是for循环遍历数组下标来访问集合元素。


如果某集合没有RandomAccess标识,那么例如LinkedList,底层遍历走的就是迭代器,反过来想也很容易想明白,LinkedList基于链表来实现,所以遍历要一个元素一个元素的遍历。。。

ArrayList的get()方法:

LinkedList的get()方法:



从图中可以看出,ArrayList的get(i) 其实就是通过数组下标直接访问元素,O(1)级别

而LinkedList需要按找链表的一半大小遍历查找对应下标是哪个节点,然后去返回该位置的元素,效率为O(n)

测试用例如下:

package Collections11;

import java.util.*;

/**
 * @Description:
 * @Author: syn
 * @Date: 2020/06/15
 **/
public class RandomAccessTest {
    public static void traverse(List list){

        if (list instanceof RandomAccess){
            System.out.println("实现了RandomAccess接口,不使用迭代器");

            for (int i = 0;i < list.size();i++){
                System.out.println(list.get(i));
            }

        }else{
            System.out.println("没实现RandomAccess接口,使用迭代器");

            Iterator it = list.iterator();
            while(it.hasNext()){
                System.out.println(it.next());
            }

        }
    }
    public static void main(String[] args) {
        List<String> arrayList = new ArrayList();
        arrayList.add("a");
        arrayList.add("b");
        traverse(arrayList);

        List<String> linkedList = new LinkedList();
        linkedList.add("c");
        linkedList.add("d");
        traverse(linkedList);
    }
}

 class RandomAccessTimeTest {

    //使用for循环遍历
    public static long traverseByLoop(List list){
        long startTime = System.currentTimeMillis();
        for (int i = 0;i < list.size();i++){
            list.get(i);
        }
        long endTime = System.currentTimeMillis();
        return endTime-startTime;
    }

    //使用迭代器遍历
    public static long traverseByIterator(List list){
        Iterator iterator = list.iterator();
        long startTime = System.currentTimeMillis();
        while (iterator.hasNext()){
            iterator.next();
        }
        long endTime = System.currentTimeMillis();
        return endTime-startTime;
    }

    public static void main(String[] args) {
        //加入数据
        List<String> arrayList = new ArrayList();
        for (int i = 0;i < 30000;i++){
            arrayList.add("" + i);
        }
        long loopTime = RandomAccessTimeTest.traverseByLoop(arrayList);
        long iteratorTime = RandomAccessTimeTest.traverseByIterator(arrayList);
        System.out.println("ArrayList:");
        System.out.println("for循环遍历时间:" + loopTime);
        System.out.println("迭代器遍历时间:" + iteratorTime);

        List<String> linkedList = new LinkedList();
        //加入数据
        for (int i = 0;i < 30000;i++){
            linkedList.add("" + i);
        }
        loopTime = RandomAccessTimeTest.traverseByLoop(linkedList);
        iteratorTime = RandomAccessTimeTest.traverseByIterator(linkedList);
        System.out.println("LinkedList:");
        System.out.println("for循环遍历时间:" + loopTime);
        System.out.println("迭代器遍历时间:" + iteratorTime);
    }
}

总结一下,使用ArrayList()遍历使用for循环还是迭代器都可以,效率基本一致,但是如果要时使用LinkedList,确使用的for循环通过下标遍历,肯定性能低下,而应该使用迭代器。

推荐文章