【JavaSE】【集合】ArrayList & Vector

在这里插入图片描述

ArrayList

1. ArrayList的无参构造

public ArrayList() {
     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

在这里插入图片描述
知识点1: 底层是Object数组
知识点2: 通过无参构造创建的ArrayList,其底层存储结构是一个缓存在方法区的空数组
知识点3: 为了避免我们反复的创建无用数组,所有通过无参构造new出来的ArrayList底层数组都指向缓存在方法区里的Object[]数组
在这里插入图片描述
在这里插入图片描述
知识点4: 对于无参构造

  • JDK1.6中,ArrayList初始化容量为10
  • JDK1.7中,初始化容量为EMPTY_ELEMENTDATA 为0
  • JDK1.8中,初始化容量为DEFAULTCAPACITY_EMPTY_ELEMENTDATA 也是0

2. 添加元素和扩容机制

private static final int DEFAULT_CAPACITY = 10;//默认容量

public boolean add(E e) {
        //1.确保当前数组的容量足够
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //2.将新元素添加到[size++]的位置
        elementData[size++] = e;
        return true;
}

扩容:
在这里插入图片描述
在这里插入图片描述

知识点1: 初次添加

  • 当原始状态为 缓存在方法区的空数组时,此时添加元素会将数组容量初始化为10;
    在这里插入图片描述

知识点2: 扩容条件

  • 当size + 1大于现有的数组长度elementData.length,就执行grow(mincapacity)

知识点3: 扩容倍数

  • oldCapacity + (oldCapacity >> 1),新容量为旧容量的1.5倍

3. ArrayList删除元素

3.1 按索引删除

 public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

知识点: 当我们用下标方式去删除元素时,如果删除的是最后一个元素,不会触发数组底层的复制,时间复杂度为O(1)。如果删除第i的元素,会触发底层数组复制n-i次,根据最坏情况,时间复杂度为O(n)。

3.2 按元素删除

public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

知识点: 用对象的方式来删除元素,只是想告诉大家,这种删除方式是用equals方法来查找元素的下标进而删除的,实际工作中很少遇到需要new一个对象去删除的情况。不建议一上来就重写equals方法,除非你有特殊的需求。

4. 插入元素

在这里插入图片描述
按照下标把元素添加到指定位置,想必大家都知道,我们直接上源码:
在这里插入图片描述

往ArrayLIst这个对象里添加的时间复杂度:

  • 如果我们不指定位置直接添加元素时(add(E element)),元素会默认会添加在最后,不会触发底层数组的复制,不考虑底层数组自动扩容的话,时间复杂度为O(1)
  • 在指定位置添加元素(add(int index, E element)),需要复制底层数组,根据最坏打算,时间复杂度是O(n)。

5. 按索引get元素

在这里插入图片描述
很简单,读取元素和数组长度无关,直接从底层数组里去拿元素

6.按索引set元素

在这里插入图片描述

7.总结

  • 在ArrayList中,底层数组存/取元素效率非常的高(get/set),时间复杂度是O(1)

  • 查找插入删除 元素效率似乎不太高,时间复杂度为O(n)。

  • 插入和删除的高效解决方案: 当我们ArrayLIst里有大量数据时,这时候去频繁插入/删除元素会触发底层数组频繁拷贝,效率不高,还会造成内存空间的浪费,这个问题在另一个类:LinkedList里有解决方案,请期待后续文章讲解。

  • 查找的高效解决方案: 查找元素效率不高,在HashMap里有解决方案,请关注后续文章。

Vector

常见面试题:Arraylist与Vector的区别是什么?

首先我们给出标准答案:
1、Vector是线程安全的,ArrayList不是线程安全的。
2、ArrayList在底层数组不够用时在原来的基础上扩展0.5倍,Vector是扩展1倍。
3、Vectir无参构造new的初始容量为10,ArrayList为空数组

相同点:
底层存储结构相同,都是数组,我们称为动态数组。

1.底层存储结构

在这里插入图片描述
实现了List接口,底层和ArrayList一样,都是数组来实现的。

2. 线程安全

  • 只要是关键性的操作,方法前面都加了synchronized关键字,来保证线程的安全性。当执行synchronized修饰的方法前,系统会对该方法加一把锁,方法执行完成后释放锁,加锁和释放锁的这个过程,在系统中是有开销的,因此,在单线程的环境中,Vector效率要差很多。(多线程环境不允许用ArrayList,需要做处理)。

  • 和ArrayList和Vector一样,同样的类似关系的类还有HashMap和HashTable,StringBuilder和StringBuffer,后者是前者线程安全版本的实现。

3. 初始化


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() {
    this(10);
}
public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

默认无参构造初始化容量为10个;

4.扩容机制

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

2倍扩容

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值