Java集合(一)

java集合分为单列集合和双列集合,分别对应List和Set。

List的常用子类结构图如下

Map常用子类结构图如下

一、ArrayList

1.ArrayList底层维护了一个Object类型的数组,当使用无参构造器时,默认大小为0。第一次添加后,大小为10,后面再次扩容,大小为原来的1.5倍

2.如果使用有参构造器指定了大小后,再次扩容是原来的1.5倍。

下面看看add源码是怎么实现的

整体来看,先判断是否要扩容,然后再赋值

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

当调用add方法后调用了ensureCapacityInternal方法确认内部容量

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

先看看参数部分,在计算容量时,首先会检查elementData是否为默认空数组,如果是,则返回DEFAULT_CAPACITY(默认容量)和minCapacity中的最大值。如果elementData不为空,则直接返回minCapacity,这个if判断只有第一次添加的时候会进去。minCapacity为集合需要的最小空间。

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

回到ensureCapacityInternal方法,modCount属性用于表示修改次数。

然后根据当前容量和元素的大小判断是否需要扩容

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

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

进入grow方法

先将元素的个数赋给oldCapacity,然后通过位运算将old值扩大原来的1.5倍。

由于第一次添加,oldCapacity的值为0,所以把minCapacity的值10赋给了oldCapacity,最后将原来的数据copy到大小为newCapacity的新数组中。

    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);
    }

这样就扩容完成了。

二、Vector

Vecror底层也是一个数组,它与ArrayList不同的是,它是线程安全的。对vector中的数据进行操作都加了synchronized锁。

分析源码

List list = new Vector();

当调用无参构造时,默认传一个10的构造方法

 public Vector() {
        this(10);
    }
public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
 public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

add方法扩容

 public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

和之前的ArrayList类似,先进入扩容,判断是否需要扩容

 private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

这里与之前不同的是扩容机制。capacityIncrement 这个值如果在实例化时没有指定的话就一直是0

每次扩容原来的2倍。如果指定了capacityIncrement,就按照capacityIncrement值来进行扩容

 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);
    }

三、LinkedList

LinkList底层维护的是一个双向链表

分析源码,在无参的构造方法中,什么都没做,就不看了。添加方法默认在尾部添加

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

新建节点,第一个节点创建,头节点和尾节点同时指向新节点。新建节点无非就是两个事,新节点的前指针,尾节点的后指针。还有判断是否只有一个节点。

void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

四、ArrayList和LinkList的比较

如果需要频繁进行插入和删除操作,且不需要随机访问元素,LinkedList可能更适合。如果需要频繁进行随机访问操作,且对插入和删除操作的性能要求不高,ArrayList可能更适合。综合选择应根据具体的使用场景和性能要求进行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值