最近在看jdk的源码,看到ArrayList的时候发现一个问题,在插入的时候,如果进行扩容,会进行两次数组的copy。
第一次:
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // 在此把整个数组copy到一个新的数组 elementData = Arrays.copyOf(elementData, newCapacity); } }
第二次拷贝:
public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); // 如果数组长度不足,将进行扩容 ensureCapacity(size+1); // Increments modCount!! // copy发生在这里,index后边的数据都需要再次copy System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
从代码可以看到,从插入点index后边的数据如果需要扩容,则会拷贝两次。一次为拷贝到新的数组,一次为整体向后挪一位。
后来考虑是不是可以创建新数组的时候拷贝两次,把index以前的数据先copy到新数组,然后index以后的数据直接向后挪一位copy入新的数组。
修改后的代码:
public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); // 如果数组长度不足,将进行扩容 // ensureCapacity(size+1); // Increments modCount!! int minCapacity = size + 1; modCount++; int oldCapacity = elementData.length; Object[] newObj = null; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3) / 2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; newObj = new Object[newCapacity]; } if (newObj != null) { System.arraycopy(elementData, 0, newObj, 0, index); System.arraycopy(elementData, index, newObj, index + 1, size - index); elementData = newObj; } else { System.arraycopy(elementData, index, elementData, index + 1, size - index); } elementData[index] = element; size++; }
因环境问题,过段时间找台测试机器把测试结果贴出来。目前在本机测效率无提升,不知道是因为机器上东西太多还是因为这个思路本身不对。
相关推荐
本资源根据个人学习和总结,主要介绍Java中ArrayList扩容机制源码的解析,主要包含文字和代码等内容,以源码的形式进行分析,详细介绍了ArrayList扩容机制的整个流程,特此将该资源分享
"Java ArrayList扩容问题实例详解" Java ArrayList扩容问题实例详解是Java编程语言中一个非常重要的知识点。ArrayList是Java中最常用的集合类之一,它提供了动态数组的功能,可以存储大量的数据。但是,ArrayList在...
Arraylist扩容原理走读
ArrayList扩容原理 ArrayList集合的底层是数组,特点是查询快增删慢。当创建一个集合时,ArrayList集合的空参构造底层数组默认长度为 0,即new Object[0]。当添加第一个元素时,掉用了ArrayList集合的add(E e)方法...
`grow(minCapacity)`是ArrayList扩容的核心方法,它会计算新的容量大小,通常是旧容量的1.5倍加上2。这样做的目的是为了平衡插入元素的成本和空间浪费。例如,如果当前容量是10,当需要添加第11个元素时,容量会增加...
对Java ArrayList的自动扩容机制示例讲解 在Java中,ArrayList是最常用的集合类之一,它提供了动态扩容的功能,能够自动地根据添加元素的数量来调整内部数组的大小,以满足元素的存储需求。今天,我们将深入探讨...
通过了解它们的扩容规则,我们可以更好地使用这些数据结构,避免常见的错误和问题。 ArrayList及HashMap的扩容规则是Java编程中非常重要的概念,了解它们的工作机制可以帮助我们编写出更加高效和可靠的代码。
Java中的ArrayList类就是基于动态数组实现的,它在扩容时会创建一个新的更大容量的数组,然后将原有元素复制到新数组中。这个过程的时间复杂度为O(n),其中n为原数组的元素数量。因此,频繁的扩容操作会带来性能开销...
JDK 1.8 中 ArrayList 底层数组的扩容机制 在 Java 语言中,ArrayList 是一个非常常用的集合类,它的底层实现是一个动态扩容的数组。当我们向 ArrayList 中添加元素时,如果数组的容量不足以容纳所添加的元素,那么...
- **扩容策略**: `ArrayList`的扩容策略不是固定的,但添加元素的操作具有常数级别的平均时间复杂度。 #### 内部实现 1. **基础结构**: - `ArrayList`内部通过一个`Object[]`数组`elementData`来存储数据。 - ...
为了减少频繁的扩容操作,可以在创建ArrayList时指定初始容量或在添加大量元素前使用`ensureCapacity`方法预先扩大容量。 - **线程安全**:ArrayList的实现不是线程安全的,意味着在多线程环境下,如果不进行外部...
- 如果对数组的动态大小调整有较高需求,可以考虑使用ArrayList代替原始数组,ArrayList在底层实现了动态扩容机制,对开发者来说更便捷。 6. 内存管理: - 扩容后,旧数组不会立即被垃圾回收,只有当所有引用都...
"Java使用数组实现ArrayList的动态扩容的方法" Java中的ArrayList是使用数组实现的,但是数组有一个缺点,就是在创建时就确定了长度,之后就不能更改长度。因此,Java官方提供了ArrayList这个可变长的容器。...
- 预估容量:在创建ArrayList时,根据预期的元素数量预设容量,可以减少扩容次数,提高性能。 - 尽量避免在循环中调用`add()`或`remove()`,因为这可能导致多次扩容或元素移动。 10. **异常处理** ArrayList的...
ArrayList基于动态数组的数据结构,因此它能够提供自动扩容的功能,同时也能够快速地进行随机访问。本篇文档将深入探讨ArrayList的内部实现原理。 首先,ArrayList是Java集合框架中List接口的一个非常重要的实现。...
ArrayList是一个基于数组实现的动态列表,可以存储任何类型的数据,并且支持动态扩容。在本实例中,我们将深入探讨ArrayList的常用操作、特性和注意事项。 一、ArrayList的构造方法 ArrayList提供了几种构造方法,...
这个方法是ArrayList扩容的核心,它的目标是确保数组的容量至少等于`minCapacity`: ```java private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { ...
当我们向ArrayList中添加元素时,如果当前数组已满,ArrayList会自动扩容。扩容的策略通常是将当前容量翻倍,以减少频繁扩容带来的性能开销。这个过程涉及到数组的复制,是ArrayList的一个重要性能考虑点。 ...
C语言版的ArrayList,具有ArrayList的基本方法增加、插入、删除、自动扩容等。
通过查看源代码,我们可以学习到如何在JavaScript环境中模拟ArrayList的行为,以及如何处理与Java中的ArrayList不同的问题,如线程安全和动态扩容等。 总的来说,ArrayList集合工具类是Java编程中的核心组件,它在...