List接口下的集合(ArrayList、LinkedList、Vector)分析比较

list接口:是connection接口的子接口,也是最常用的接口。此接口对connection接口进行了大量的扩充。里面的内容是允许重复允许为空并且有序(插入顺序有序)。

1、ArrayList

在这里插入图片描述

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable

1.1ArrayList特点

ArrayList实现了List, RandomAccess, Cloneable, java.io.Serializable接口,具有以下特点:
1、List:存放单值,里面的内容允许重复允许为空并且有序(插入的顺序)
2、Cloneable:集合可以使用clone方法
3、Serializable:可以序列化
4、RandomAccess:ArrayList可以被随机访问
5、Iterator:ArrayList可以使用迭代器遍历ListIterator:是Iterator接口的子接口,可以进行双向输出

1.2ArrayList源码中的一些方法介绍

增加方法:

add(int index,type element); //向指定下标添加元素
add(type element);//在List末尾添加元素
//批量添加
addAll(Collection c)//在集合末尾添加集合类元素   两个集合的并集
addAll(int index, Collection c)//在集合指定位置添加集合类元素

删除方法:

remove(Object o)//删除元素
remove(int index)//删除下标对应的元素
removeAll(Collection c)//在集合删除集合类元素
//list.removeAll(list1)  从list中移除(list和list1的公共元素) 
retainAll(Collection c)//求交集,移除非交集元素
//list.retainAll(list1)  list保留和list1的公共元素,其他元素删除

1.3两个ArrayList交集/不重复并集/差集

import java.util.ArrayList;

public class ArrayList2 {
    public static void main(String[] args){
        ArrayList list = new ArrayList();
        ArrayList list1= new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list1.add(1);
        list1.add(2);
        list1.add(5);
        list1.add(6);
        list1.add(7);
/**
 *  list.retainAll(list1)  list保留和list1的公共元素,其他元素删除
 *  list.retainAll(list1);//1 2 3 4    1 2 5 6 7
 * 遍历结果:交集
 * 1 2
 */
/**
 *  list.removeAll(list1)  从list中移除(list和list1的公共元素) 
 *  list.removeAll(list1);//1 2 3 4    1 2 5 6 7
 * 遍历结果:差集
 * 3 4
 */
        list.removeAll(list1);//list 1 2 3 4   list1 1 2 5 6 7     list---->3 4
        list1.addAll(2,list);//list1 1 2 5 6 7  list 3 4
        System.out.println("不重复并集:");
        for (int i = 0; i < list1.size(); i++) {
            System.out.print(list1.get(i) + "  ");
        }
    }
}

1.4实现MyArrayList

package JiHe.OneArrayList;

import java.util.*;

public class MyArrayList<T> {
    private Object[] elementData;//泛型数组 ArrayList的底层数据结构
    private int size;//数组中存放的元素个数(不是容量)
    private int DEFULT_SIZE =10;//ArrayList默认大小
    private static final Object[] EMPTY_ELEMENTDATA = {};//定义一个空数组,
    /**
     * 无参构造函数:
     * - 创建一个 空的 ArrayList,此时其内数组elementData = {}, 长度为 0
     * - 当元素第一次被加入时,扩容至默认容量 10
     */
    public MyArrayList() {
        elementData = EMPTY_ELEMENTDATA;
    }

    private class Itr implements Iterator<T>{  //具体迭代器角色
        public int cur;  //当前元素下标
        @Override
        public boolean hasNext() {  //判断是否遍历结束,当cursor不等size时表示有下个元素
            return cur != size;
        }

        @Override
        public T next() {    //获取当前元素的方法,并且移动到下一个元素的位置
            return (T)elementData[cur++];
        }

        @Override
        public void remove() {  //移除当前对象的方法
           MyArrayList.this.remove(cur);
        }
    }
    private class ListItr extends Itr implements ListIterator<T>{
        ListItr(int index) {
            super();
            cur = index;
        }
        @Override
        public boolean hasPrevious() {
            return false;
        }

        @Override
        public T previous() {
            return null;
        }

        @Override
        public int nextIndex() {
            return 0;
        }

        @Override
        public int previousIndex() {
            return 0;
        }

        @Override
        public void set(T t) {

        }

        @Override
        public void add(T t) {

        }
    }


    public Iterator<T> iterator() {
        return new Itr();
    }
    public ListIterator<T> listIterator() {
        return new ListItr(0);
    }
    public int getSize() {
        return size;
    }

    //扩容方法
    private void grow(int size){
        //如果数组原来是空数组,扩容从0到默认大小10,否则扩容至原来大小的1.5倍
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if(newCapacity - size < 0){
            newCapacity = DEFULT_SIZE;
        }
        elementData =Arrays.copyOf(elementData,newCapacity);
    }

    //检查下标越界
    private void rangeCheck(int index){
        if(index >= size || index < 0){
            throw new IndexOutOfBoundsException();
        }
    }
    //检查ArrayList容量,插入元素是否需要进行扩容操作
    private void ensureCapacity(int size){
        if(size>elementData.length){
            grow(size);
        }
    }
    //增删改查方法
    //增加操作


    public void add(T value){//尾部添加
        //判断ArrayList的容量大小
        ensureCapacity(size+1);
        elementData[size++] = value;
    }

    public void add(int index,T value){//向指定下标添加元素(数据的移动) ArrayList不适合随机插入
        //判断下标是否越界
        rangeCheck(index);
        ensureCapacity(size+1);
        System.arraycopy(elementData,index,elementData,index+1,size -index);
        //原数组 原数组起始位置 目标数组 目标数组起始位置 移动元素个数
        elementData[index] = value;
        size++;
    }

    //删除操作
    public void remove(int index){ //删除某个下标元素
        rangeCheck(index);
        System.arraycopy(elementData,index+1,elementData,index,size - index-1);
        elementData[--size] = null;
//        elementData[size-1] =null;//GC
//        size--;
    }

    public boolean remove1(Object value){//删除某个元素
        //遍历数组,如果不存在该元素,不发生改变,如果含有该元素,将该元素删除,数据移动
        if(value == null){    //ArrayList允许空值
            for(int i = size;i>=0;i--){     //int i =0;i< size;i++这种情况下  如果数组中有重复值只删除第一个值
                if(elementData[i] ==value){
//                    System.arraycopy(elementData,i+1,elementData,i,size -i-1);
//                    elementData[--size] = null;
                    fastRemove(i);
                }
                return true;
            }
        }else{
            for(int i = size;i>=0;i--){
                if(value.equals(elementData[i])){
                  fastRemove(i);
                }
            }
            return true;
        }
        return false;
    }
    private void fastRemove(int index){
        System.arraycopy(elementData,index+1,elementData,index,size -index-1);
        elementData[--size] = null;
    }
    //查
    //获取某位置的元素
    public T get(int index){
        //判断下标是否越界
        rangeCheck(index);
        return (T)elementData[index];
    }
    //查找数组中是否有该元素
    public boolean contains(Object value){
//        存在问题,如果数组中有空元素,如size=3,elementData.length = 4,存在空指针异常
//        for(int i = 0;i<size;i++){
//            if(elementData[i].equals(value)) {
//                return true;
//            }
//        }
//        return false;
        return indexOf(value) >=0; //根据元素下标来判断
   }
    public int indexOf(Object o) {  //找到元素所对应的下标
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //改
    //修改某位置的元素
    public void set(int index,T value){
        rangeCheck(index);
        elementData[index] = value;
    }
    //查找是否包含元素
}

2、LinkedList

在这里插入图片描述

public class LinkedList
    extends AbstractSequentialList
    implements List, Deque, Cloneable, java.io.Serializable

2.1 LinkedLis特点

LinkedList:既是list接口下的集合,也是queue接口下的集合
LinkedList 是一个继承于AbstractSequentialList的双向链表。底层是使用了链表数据结构实现的.它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。存放单值,里面的内容允许重复允许为空并且有序(插入的顺序)
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,LinkedList支持序列化,能通过序列化去传输。LinkedList可以被随机访问
Iterator:LinkedList可以使用迭代器遍历ListIterator:是Iterator接口的子接口,可以进行双向输出;private class ListItr implements ListIteratorprivate class DescendingIterator implements Iterator,进行从前往后遍历

2.2MyLinkedList实现

package JiHe.OneLinkedList;

import java.util.Iterator;

public class MyLinkedList<T> {
    private Node<T> first;//头指针
    private Node<T> last;//尾指针
    private int size;//数据数量

    public MyLinkedList() {
    }

    public void add(T item){//尾插法
        Node<T> l = last;
        Node<T> newNode = new Node(item,l,null);
        if(l == null){
            first = newNode;
        }else{
            l.next = newNode;//增加判断条件,如果last为空会出现空指针异常
        }
        last = newNode;
        size++;
    }
    private Node node(int index){//获取index位置的结点
        if (index < (size >> 1)) {//如果index是链表的前半部分,从前往后遍历
            Node<T> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {//如果index是链表的后半部分,从后往前遍历
            Node<T> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
    //检查index合法性
    private void checkIndex(int index){
        if(index >size || index <0){
            throw new IndexOutOfBoundsException();
        }
    }
    public void add(int index, T item){//在指定索引位置之前插入元素e
        //判断index是否合法,如果s为空,说明超过了size的值
        //如果index=size,即尾插
        checkIndex(index);
        if(index == size){
            add(item);
            return;
        }
        Node<T> s = node(index);
        Node<T> pre = s.prev ;
        Node<T> newNode = new Node(item,pre,s);
        s.prev = newNode;
        if(pre == null){
            first = newNode;
        }else{
            pre.next = newNode;
        }
        size++;
    }
    public void remove(int index){
        checkIndex(index);
        Node<T> s = node(index);
        T element = s.item;
        Node<T> prev = s.prev;
        Node<T> next = s.next;
        //四种情况(分步思考)
        //只有s这个结点(prev ==null, next == null)
        //s是头结点(prev ==null,next != null)
        //s是尾巴结点(prev != null,next == null)
        //s是链表中间某个结点(prev != null , next != null)
        if(prev == null){
            first = next;
        }else{
            prev.next = next;
            s.prev = null;
        }
        if(next == null){
            last = prev;
        }else{
            next.prev = prev;
            s.next = null;
        }
        element = null;
        size--;
    }
    public void set(int index,T value){
        checkIndex(index);
        Node<T> node = node(index);
        node.item = value;
    }
    public T get(int index){
        checkIndex(index);
        Node<T> node = node(index);
        return node.item;
    }
    public int size(){
        return size;
    }
    private static class Node<T>{
        T item;
        Node<T> prev;
        Node<T> next;
        public Node(T item, Node<T> prev, Node<T> next) {
            this.item = item;
            this.prev = prev;
            this.next = next;
        }
    }
    //迭代器实现
    private class MyIterator implements Iterator<T> {
        public int curIndex;//当前结点下标
        @Override
        public boolean hasNext() {//判断是否遍历结束,判断当前结点下标和size关系
            return curIndex < size;
        }

        @Override
        public T next() {//获取当前元素的方法
            if(curIndex == 0){  // 当前结点是头结点
                curIndex++;
                return first.item;
            }else{
                curIndex++;
                first = first.next;
                return first.item;
            }
        }

        @Override
        public void remove() {//移除当前对象的方法
            MyLinkedList.this.remove(curIndex);
        }
    }
    public Iterator<T> iterator() {
        return new MyIterator();
    }
}

3.Vector

public class Vector
    extends AbstractList
    implements List, RandomAccess, Cloneable, java.io.Serializable

可以发现Vector和ArrayList继承与实现相同,故Vector的特点和ArrayList相似

4.List接口下的集合比较

4.1LinkedList与ArrayList的区别

LinkedList与ArrayList在性能上各有优缺点,都有各自适用的地方,总结如下:

  1. 底层结构:ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。LinkedList不支持高效的随机元素访问。
  2. ArrayList的空间浪费主要体现在在l数组的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间(前驱,后继),就存储密度来说,ArrayList是优于LinkedList的。
  3. 使用场景:当操作是在一列数据的后面添加删除数据,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能,当你的操作是在一列数据的随机添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了,LinkedList更适合随机添加删除方法比较频繁的操作,不需要进行数据的移动。

4.2Vector和ArrayList的区别

主要体现在 源码上:

  1. 底层数据结构:Vector和ArrayList底层数据结构都是数组;
  2. 构造函数:ArrayList初始数组大小为空,添加第一个元素时数组容量变为10; Vector初始数组大小为10;
  3. grow()方法:ArrayList中添加第一个元素时数组容量0变为10,之后成1.5倍扩容; Vector中如果capacityIncrement大于0,容量增加capacityIncrement个,如果capacityIncrement小于0,即2倍扩容(默认情况下Vector二倍扩容)。扩容方式vector更合理。
  4. 线程安全:Vector所有方法都添加了synchronized锁,所以Vector是线程安全的集合,但是加锁操作非常耗时,效率低;而ArrayList是线程不安全的集合。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值