【深入分析List接口】ArrayList LinkedList Vector

本文深入探讨了Java集合框架中的ArrayList, LinkedList和Vector,详细分析了它们的实现原理、遍历方式及常用方法。ArrayList基于可变大小的数组,适合随机访问;LinkedList采用双向链表实现,适合频繁的添加和删除操作;Vector线程安全但效率较低,同样基于数组。三者在并发、性能和用途上有明显区别。
摘要由CSDN通过智能技术生成

❤写在前面
❤博客主页:努力的小鳴人
❤系列专栏:JavaSE超详总结😋
❤欢迎小伙伴们,点赞👍关注🔎收藏🍔一起学习!
❤如有错误的地方,还请小伙伴们指正!🌹

对于【10章Java集合】几张脑图带你进入Java集合的头脑风暴🔥 的拓展分析


一、基础知识

  1. 特点:有序的,允许重复元素顺序可以是自然排序或按对象加入到集合的顺序排序
  2. 遍历:
    ① Iterator迭代器方式
    ② 增强for循环
    ③ 普通的循环
  3. List接口常用方法
    在这里插入图片描述
  4. JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector

二、ArrayList

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

ArrayList继承了AbstractList,且实现了List, RandomAccess, Cloneable, Serializable接口
ArrayList是一个可变大小的数组

🔥无参构造函数

默认情况下,数组为一个空数组

//无参构造函数
public ArrayList() {
    super();//因为继承了AbstractList,所以调用AbstractList的构造函数
    //这里是把数组设置为空数组对象
    this.elementData = EMPTY_ELEMENTDATA;
}

🔥源码分析

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8683452581122892189L;

    //默认数组大小为10
    private static final int DEFAULT_CAPACITY = 10;
    //空数组对象
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //ArrayList底层基于该数组实现
    private transient Object[] elementData;
    //ArrayList中实际数据的大小
    private int size;

    //带有初始化容量大小的构造函数
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        //使数组初始化为指定容量大小
        this.elementData = new Object[initialCapacity];
    }

    //无参构造函数
    public ArrayList() {
        super();
        //这里是把数组设置为空数组对象
        this.elementData = EMPTY_ELEMENTDATA;
    }

    //创建一个包含Collection的ArrayList
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

    //将当期容量值设置为实际元素个数
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }

    //确保ArrayList容量,如果    
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
                // any size if real element table
                ? 0
                // larger than default for empty table. It's already supposed to be
                // at default size.
                  : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private void ensureCapacityInternal(int minCapacity) {
        //初始化时候,elementData是为空数组对象EMPTY_ELEMENTDATA,所以会去设置minCapacity的值
        if (elementData == EMPTY_ELEMENTDATA) {
            //设置minCapacity值,比较minCapacity和默认容量(DEFAULT_CAPACITY=10)
            //把最大值赋值给minCapacity
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //确定明确的容量大小
        ensureExplicitCapacity(minCapacity);
    }

    //确定明确的容量大小
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    //最大数组大小=Integer.MAX_VALUE - 8
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //扩容方法
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }

三、LinkedList

双向链表,内部没有声明数组,而是定义了Node类型的first和last,用于记录首末元素

  1. 定义
public class LinkedList<E> extends AbstractSequentialList<E> 
		implements List<E>, Deque<E>, Cloneable, java.io.Serializable

LinkedList继承了AbstractSequentialList,并且实现了List, Deque, Cloneable, Serializable接口
LinkedList底层是基于链表实现的

  1. LnkedList里面定义了一个私有静态内部类Node
    Node有三个成员变量,item, next, prev.从字面上理解为本身, 下一个元素,前一个元素
private static class Node<E> {
        //本身
        E item;
        //下一个元素
        Node<E> next;
        //前一个元素
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

在这里插入图片描述

🔥原理

●LinkedList 通过双向链表去实现的,一个内部类:Entry:Entry是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值,上一个节点,下一个节点
●LinkedList的克隆函数,即是将全部元素克隆到一个的LinkedList对象中。
●LinkedList实现java.io.Serializable,当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”
●由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法:提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false等)

🔥遍历方式

LinkedList支持多种遍历方式

package ListTest;
 
import java.util.ArrayList;
import java.util.Iterator;
 
public class Test {
	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(7);
		list.add(6);
		list.add(5);
		list.add(8);
		list.add(9);
		list.add(11);
		//通过迭代器遍历
		Iterator<Integer> iterator = list.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next()+" ");
		}
		System.out.println("\n--------------------------");
		//for循环遍历
		for (Integer integer : list) {
			System.out.print(integer+" ");
		}
		System.out.println("\n--------------------------");
		//随机访问,通过list.get(i)获得索引值去遍历,不建议
		for(int i=0;i<list.size();i++) {
			System.out.print(list.get(i)+" ");
		}
		
	}
	
}

随机访问的方式去遍历LinkedList是低效的,采用逐个遍历的方式较高效

🔥常用方法

在这里插入图片描述

四、Vector

Vector 是矢量队列,底层是数组
Vector中的操作是线程安全的,效率不高

🔥构造函数

 //Vector和ArrayList一样,底层基于该数组实现
protected Object[] elementData;
//这个相当于ArrayList里面的size
protected int elementCount;
//当Vector的大小大于其容量时,Vector的容量自动增加的量。 
protected int capacityIncrement;
//带容量和容量自动增加量的参数的构造函数
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        //初始化数组
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    //给定容量的构造函数
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    //无参构造函数
    public Vector() {
        //初始化数组,大小为10
        this(10);
    }

在new Vector()的时候,vector内数组已经被初始化了,并且数组的长度为10

🔥原理

●Vector实际通过一个数组保存数据,当构造Vecotr时使用默认构造函数,则Vector的默认容量大小是10
●当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍
●Vector的克隆函数,即是将全部元素克隆到一个数组中

🔥遍历方式

  1. 通过迭代器遍历。即通过Iterator去遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}
  1. 随机访问,通过索引值去遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}
  1. for循环
Integer value = null;
for (Integer integ:vec) {
    value = integ;
}
  1. Enumeration遍历
Integer value = null;
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
    value = (Integer)enu.nextElement();
}

🔥常用方法

在这里插入图片描述

五、ArrayList LinkedList Vector 三者区别

主要区别在于实现方法的不同,所有对不同的操作具有不同的效率

  1. ArrayList
    ArrayList是一个可以改变大小的,线程不同步(不支持并发)的数组,内部值可以为null。 当更多的元素加入到ArrayList中时,大小会自动增加,内部元素可以直接通过get/set方法进行访问,因为ArrayList本质上即使一个数组
  2. LinkedList
    LinkedList底层是基于双链表实现的在添加和删除元素时具有比ArrayList更好的性能。但是在get/set方面要弱于ArrayList(前提是这些对比是在数据量很大或者操作很繁琐的情况下),LinkedList内部值可以为null,但是当我们调用值为null的元素的时候会出现NullPointerException
    LinkedList更适合①没有大量的随机访问操作②有大量的add/remove操作。
  3. Vector
    属于线程同步(支持并发)的数组,并且内部值也可以为null

🎁总结ArrayList和Vector它们底层实现为数组,值可为null, ArrayList不支持并发,Vector支持并发;LinkedList底层基于双链表,所以在add/remove元素时比ArrayList要快
👌 作者算是一名Java初学者,文章如有错误,欢迎评论私信指正,一起学习~~
😊如果文章对小伙伴们来说有用的话,点赞👍关注🔎收藏🍔就是我的最大动力!
🚩不积跬步,无以至千里书接下回,欢迎再见🌹

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的小鳴人

鳴人将永远记住您的恩惠

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值