集合框架2-List接口下的三个常用实现类(ArrayList、LinkenList、Vector)讲解-第一阶段-第十三天

List接口的使用

首先List接口是从Collection接口那里继承而来,特点是有序有重复
有序:每个元素都有一个固定的下标,和数组类似
有重复:可以有多个重复的元素

List接口中与下标相关的对应方法

  1. add(int index, Object object),添加元素到指定序列
  2. get(int index)根据下标直接获取某个位置的元素值并返回
  3. set(int index,Object e)修改指定下标位置的元素值
  4. remove(int index) 根据下标删除指定位置的元素

注意:如果按照一个int类型的数据内容进行删除,需要手动进行包装,否则将参数理解为下标

ArrayList集合

ArrayList集合继承了List接口,重写了接口中的方法,在这些方法包含了能够对下标进行处理的方法。在ArrayList中还是用数组实现,所以可以近似把它当做数组运用。

ArrayList实现类的原理说明

ArrayList定义的常用属性

    //默认初始数组容量
   private static final int DEFAULT_CAPACITY = 10;

    //储存集合中实例对象
   private static final Object[] EMPTY_ELEMENTDATA = {};

    //共享的空数组实例用于默认大小的空实例。将其与EMPTY ELEMENTDATA区分开来,
    //以便知道添加第一个元素时要膨胀多少。
   private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //数组列表的元素存储在数组缓冲区中。数组列表的容量就是这个数组缓冲区的长度。
    //任何带有elementData == DEFAULTCAPACITY的*空ArrayList将在添加第一个元素时扩展为DEFAULTCAPACITY。
   transient Object[] elementData; // non-private to simplify nested class access
   
   //储存元素个数
   private int size;

1. 在ArrayList中保存的数据都是保存在对象数组EMPTY_ELEMENTDATA

//ArrayList中属性设置
private static final Object[] EMPTY_ELEMENTDATA = {};

2. 在ArrayList集合中提供了三种构造方法如下图

在这里插入图片描述

2.1 使用无参构造时提供了一个默认初始化容量为10,但是不立即创建对象,这其实是一种“延迟策略”,在客户正真要使用的时候才分配元素对应的空间
	public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
2.2 在使用构造器的时候传入一个整数,表示设置初始容量,但是在设置初始容量的时候尽量要防止扩容,因为扩容消耗内存,效率不高,所以一般推荐空参构造
    public ArrayList(int initialCapacity) {
       if (initialCapacity > 0) {
           this.elementData = new Object[initialCapacity];
       } else if (initialCapacity == 0) {
           this.elementData = EMPTY_ELEMENTDATA;
       } else {
           throw new IllegalArgumentException("Illegal Capacity: "+
                                              initialCapacity);
       }
   }
2.3 在使用构造器的过程中还可以传入一个实现collection接口的集合,供初始化
   public ArrayList(Collection<? extends E> c) {
       elementData = c.toArray();
       if ((size = elementData.length) != 0) {
           // c.toArray might (incorrectly) not return Object[] (see 6260652)
           if (elementData.getClass() != Object[].class)
               elementData = Arrays.copyOf(elementData, size, Object[].class);
       } else {
           // replace with empty array.
           this.elementData = EMPTY_ELEMENTDATA;
       }
   }

3. ArrayList添加元素过程

	public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //确定数组的容量是否足够,并传入添加当前元素需要的最小容量  
        elementData[size++] = e;//将新元素的值添加到内部数组的最后并对元素个数进行增
        return true;//返回添加操作的状态
	}
	private void ensureCapacityInternal(int minCapacity) {
		//如果数组为空
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	//如果是第一次添加就设置容量为10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
	private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        //如果需要的长度比现有长度大,那么就执行grow方法
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
	private void grow(int minCapacity) {
        // 首先复制原有数组长度
        int oldCapacity = elementData.length;
        //将原有数组长度设置为原来的1.5倍
        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;
    }

ArrayList特点

数组属于线性表这种数据结果,查找和检索还有遍历的效率非常高 时间复杂度为O(1),但是增删的效率非常低O(n)

LinkedList实现类

LinkedList常用方法

  1. addFirst:添加到集合第一个元素
  2. addLast:添加到集合最后一个元素
  3. getFirst: 获取第一个集合元素
  4. getLast: 获取最后一个集合元素
  5. removeFirst:删除集合第一个元素
  6. removeLast:删除集合最后一个元素
	LinkedList list=new LinkedList();		
	list.add("111");
	list.add("222");
	list.add("333");
	list.addFirst("666");//在头部添加一个新元素
	list.addLast("999");//在尾部添加一个新元素		
	Object data=list.removeFirst();//移除最前面的元素并返回
	list.removeLast();//移除列表中最后一个元素并返回
	list.getFirst();//获取头部元素并返回
	list.getLast();//获取尾部元素并返回
	System.out.println(data);		
	for (Object object : list) {
	    System.out.println(object);
	}

LinkedList原理分析

LinkedList底层使用的双向数据链表,每个元素称为一个“节点”,每个节点由三个部分组成:左边存储上一个节点的地址,中间存储本身的数据,右边存储下一个节点的地址,每个节点在内存中不要求是连续的,相比于数组来说可以有效的利用一些分散的内存碎片

代码实现

	//在LinkedList中定义的一个静态内部类,描述我们链表的每个节点
	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;
        }
    }

添加元素代码分析

void linkLast(E e) {
	//记录之前最后一位元素
    final Node<E> l = last;
    //将此次添加元素prev指针指向之前最后一位元素
    final Node<E> newNode = new Node<>(l, e, null);
    //添加后那么此元素即为最后一位
    last = newNode;
    //如果为空那么说明此次添加为第一个元素
    if (l == null)
        first = newNode;
    //否则将之前的最后一位元素naxt指针指向此元素
    else
        l.next = newNode;
    size++;
}

Vector实现类

该集合的使用包括原理和ArrayList完全一样,不同的是大部分方法都有一个synchronized修饰,用来保证线程安全的,其余操作与ArrayList用法几乎一致。
之所以现在Vector集合运用的少,是因为现在处理线程问题很多不是非常需要synchronized来解决

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值