ArrayList/Vector的源码分析

ArrayList

ArrayList 是动态数组,其实就是Array的复杂版本,它提供了动态增加和减少元素的功能,实现了ListRandomAccess, Collection接口,ArrayList不是线程安全的,建议在单线程中使用ArrayList

ArrayList 包含两个重要属性分别是:

/**
* elementData;
* transient 关键字修饰表示防止此字段被序列化
* 避免了浪费资源去存储没有的数据
* size:
* elementData中已存放的元素的个数,注意:不是elementData的容量
* 
*/
transient Object[] elementData;
private int size;

因为 elementData无法被序列化, 所以ArrayList 的序列化和反序列化依赖writeObjectreadObject方法来实现

/**
 * Save the state of the <tt>ArrayList</tt> instance to a stream (that
 * is, serialize it).
 *
 * @serialData The length of the array backing the <tt>ArrayList</tt>
 *             instance is emitted (int), followed by all of its elements
 *             (each an <tt>Object</tt>) in the proper order.
 */
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);

    // Write out all elements in the proper order.
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}
    
/**
 * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
 * deserialize it).
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // Read in size, and any hidden stuff
    s.defaultReadObject();

    // Read in capacity
    s.readInt(); // ignored

    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

ArrayList 中添加元素单个元素有两种方式
第一种:将单个元素添加到尾部,并将size + 1。

/**
 * 向elementData中添加元素
 */
public boolean add(E var1) {
    this.ensureCapacityInternal(this.size + 1);//确保对象数组elementData有足够的容量,可以将新加入的元素e加进去
    this.elementData[this.size++] = var1;//加入新元素e,size加1
    return true;
}

/**
 * 确保数组的容量足够存放新加入的元素,若不够,要扩容
 */
public void ensureCapacity(int minCapacity) {
    modCount++;
    int oldCapacity = elementData.length;//获取数组大小(即数组的容量)
    //当数组满了,又有新元素加入的时候,执行扩容逻辑
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        int newCapacity = (oldCapacity * 3) / 2 + 1;//新容量为旧容量的1.5倍+1
        if (newCapacity < minCapacity)//如果扩容后的新容量还是没有传入的所需的最小容量大或等于(主要发生在addAll(Collection<? extends E> c)中)
            newCapacity = minCapacity;//新容量设为最小容量
        elementData = Arrays.copyOf(elementData, newCapacity);//复制新容量
    }
}

第二种:将单个元素添加到指定位置。

public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);//确保对象数组elementData有足够的容量,可以将新加入的元素e加进去
    
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);//复制数组,将值往后移动
    elementData[index] = element;
    size++;
}
/**
* 添加元素时判断elementData是否为空,为空则设置elementData的大小为10
*/
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

由此可见两种添加方式前者比后者节省资源消耗。

Vector

Vector 也是实现于List接口,底层数据结构和ArrayList类似,也是动态数组存放数据,不过是在 add() 方法的时候使用 synchronized 进行同步写数据,与ArrayList不同的是Vector 线程安全,但是开销较大,所以 Vector 是一个同步容器并不是一个并发容器。

/**
* 在对象数组中尾部添加单个元素和在指定位置添加单个元素
* 使用synchronized 进行同步写数据
*/
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

public void add(int index, E element) {
    insertElementAt(element, index);
}
public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount);
    }
    ensureCapacityHelper(elementCount + 1);
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于LSTM的财务因子预测选股模型LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值