后端---Java中ArrayList和LinkedList区别和联系

ArrayList和LinkedList的区别和联系

在一个多月之前,我曾写过一篇博客想要迅速简洁的了解Java中所有的集合类型(List、Set、Map),然后一个月多后的我不得已又抱起《Java核心卷I 》仔细研读,这是为什么呢???

是因为“温故而知新”还是因为“书读百遍其义自显”????

都不是!!!

因为我忘完了啊!

关于List和Set、Map的博客,这里给出链接 

 java中List、Set、Map之间的关系 https://blog.csdn.net/weixin_42504145/article/details/83119088

一.初识List 

首先我们从一副图来看ArrayLIst和LinkedList的关系,很明显他两都实现了Java给出的List集合这个接口,但是我要说的是这个图并不完善!!!

我们来看完善的定义: 

// lang java
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Queue<E>, Cloneable, Serializable

从继承关系来看:

在这个引用中我们能看到的ArrayList集成了AbstractList这个父类,虽然Linkedlist继承的是AbstractSequentialList这个父类,但这个父类仍继承与AbstactList这个类,所有并没有太大区别。 

从接口实现关系来看:

联系:无论是ArrayList和LinkedList都实现了List<E>、Cloneable、Serializable这三个接口。List接口会作为重点在下面详细介绍,先来看另外两个接口,Cloneable接口是一个标记接口,也就是没有任何内容,这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportException。Object中默认的实现是一个浅拷贝,也就是表面拷贝,如果需要实现深层次拷贝的话,必须对类中可变域生成新的实例。Serializable接口是一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。

区别:ArrayList实现了随机访问的接口RandomAccess,LinkedList实现了Quene的接口。ArrayList是基于动态数组实现的list,而LinkedList是基于链表实现的list。所以,ArrayList拥有着数组的特性,LinkedList拥有着链表的特性。

我们再来看List这个接口

 List集合是一个有序集合。元素会增加到容器中的特定位置。可以采用两种方式访问元素:使用迭代器访问,或者使用一个整数索引来访问。后一种方式称为随机访问,因为这样可以按任意顺序访问元素。与之不同的是,使用迭代器访问时,必须顺序地访问元素。

List接口定义了多个用于随即访问的访问:

void add(int index,E element)

void remove(int index)

E get(int index)

E set(int index,E element)

二. ArrayList和LinkedList

ArrayList 

ArrayList实现了List接口,它是以数组的方式来实现的,数组的特性是可以使用索引的方式来快速定位对象的位置,因此对于快速的随机取得对象的需求,使用ArrayList实现执行效率上会比较好. 

ArrayListDemo:

public class ArrayListDemo {  
  
    public static void main(String[] args) {  
          
        List<String> userlist = new ArrayList<String>();  
        userlist.add("yulon");  
        userlist.add("xiaoyun");  
        userlist.add("羽龙共舞");  
        System.out.println("使用普通for循环:");  
        for(int i=0; i<userlist.size(); i++){  
            System.out.print(userlist.get(i)+" ");  
        }  
        System.out.println();  
        System.out.println();  
        System.out.println("使用Iterator迭代器:");  
        Iterator it = userlist.iterator();  
        while(it.hasNext()){  
            System.out.print(it.next()+" ");  
        }  
        System.out.println();  
        System.out.println();  
        System.out.println("使用增强for循环:");  
          
        for(String s : userlist){  
            System.out.print(s+" ");  
        }  
    }  
}  

这里有三种输出输出List的方法,我们不建议用for循环输出List,因为在下面的例子中用for循环输出LinkedList会造成一个很严重的失误,因为LinkedList底层是用链表实现的,如果使用get()方法获取某个元素的值,LinkedList每次都会从头开始遍历极其损耗性能,我们建议用Iterator和for-each方法来输出List集合,关于for-each方法内部也是生存成了一个Iterator对象,只不过在底层进行了封装,我们看不见而已。如果关于Iterator不懂的可以参考我这篇博客:

https://blog.csdn.net/weixin_42504145/article/details/85210723  Java中Iterator(迭代器)的用法及其背后机制的探究

LinkedList

LinkedList是采用链表的方式来实现List接口的,它本身有自己特定的方法,如: addFirst(),addLast(),getFirst(),removeFirst()等. 由于是采用链表实现的,因此在进行insert和remove动作时在效率上要比ArrayList要好得多!适合用来实现Stack(堆栈)与Queue(队列),前者先进后出,后者是先进先出.

public class StringStack {  
    private LinkedList<String> linkedList   
    = new LinkedList<String>();  
  
    /** 
     * 将元素加入LinkedList容器 
     * (即插入到链表的第一个位置) 
     */  
    public void push(String name){  
        linkedList.addFirst(name);  
    }  
    /** 
     * 取出堆栈中最上面的元素 
     * (即取出链表linkedList的第一个元素) 
     * @return 
     */  
    public String getTop(){  
        return linkedList.getFirst();  
    }  
    /** 
     * 取出并删除最上面的元素 
     * (即移出linkedList的第一个元素) 
     * @return 
     */  
    public String pop(){  
        return linkedList.removeFirst();  
    }  
    /** 
     * 获取元素个数 
     * @return 
     */  
    public int size(){  
        return linkedList.size();  
    }  
      
    /** 
     * 判断堆栈是否为空 
     * (即判断 linkedList是否为空) 
     * @return 
     */  
    public boolean isEmpty(){  
        return linkedList.isEmpty();  
    }  
    //测试  
    public static void main(String[] args) {  
        StringStack stack = new StringStack();  
        stack.push("yulon");  
        stack.push("xiaoyun");  
        stack.push("羽龙共舞");  
        System.out.print("第一个元素是:\t");  
        System.out.println(stack.getTop());  
        System.out.println();  
        System.out.println("全部元素:");  
        while(!stack.isEmpty()){  
            System.out.println("\t"+stack.pop());  
        }  
    }  
}  

三.总结 

下面这些区别是我们都知道的:

   1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous)
     2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 
     3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 

我们再来自己总结总结ArrayList和LinkedList的区别: 

ArrayList和LinkedList在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下: 

  • 对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。
  • 在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
  • LinkedList不支持高效的随机元素访问。
  • ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
  • 可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

参考链接:
https://blog.csdn.net/bjzhuhehe/article/details/72230559

https://www.cnblogs.com/Jacck/p/8034900.html

https://www.cnblogs.com/lxq0309/p/3655742.html

猜你喜欢

转载自blog.csdn.net/weixin_42504145/article/details/85230422