`
yuxuguang
  • 浏览: 139153 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ArrayList扩容问题

    博客分类:
  • java
 
阅读更多

最近在看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++;
	}

 
 因环境问题,过段时间找台测试机器把测试结果贴出来。目前在本机测效率无提升,不知道是因为机器上东西太多还是因为这个思路本身不对。

  • 大小: 13.1 KB
  • 大小: 12.1 KB
0
0
分享到:
评论
5 楼 bitray 2015-03-18  
yuxuguang 写道
bambooman 写道
难有显著提高,反而把代码逻辑搞复杂了。
1、System.arraycopy 本身效率很高,多复制一次差不到哪里去

2、确保容量的扩容操作很少能得到执行。 因为每次扩容大约为 50%。 参见
int newCapacity = (oldCapacity * 3)/2 + 1; 


个人认为list扩容操作里数组的复制是最耗性能的,如果不能预估list的大小,list执行扩容的机会很多。而且感觉修改后代码的逻辑并没有复杂化,等有时间搞个压力测试,看看性能的提升。

频繁扩容是耗时的,他拆分成初始化一个更大的数组,元素拷贝。
旧数组的回收不用考虑。
但是扩容几次,其实影响不大。真的担心的话,最好初始化把数组大小调整的差不多状态
4 楼 laogao3232 2015-03-13  
应该看到,数组整体多拷贝了一次。所以数组越大,性能提升越明显。
3 楼 小橙子 2015-03-12  
我觉得理论上是提高了点性能,但是几乎可以忽略吧。扩容几次后,很难有机会扩容了。大部分ArrayList存储的数据都是很少的。
2 楼 yuxuguang 2015-03-12  
bambooman 写道
难有显著提高,反而把代码逻辑搞复杂了。
1、System.arraycopy 本身效率很高,多复制一次差不到哪里去

2、确保容量的扩容操作很少能得到执行。 因为每次扩容大约为 50%。 参见
int newCapacity = (oldCapacity * 3)/2 + 1; 


个人认为list扩容操作里数组的复制是最耗性能的,如果不能预估list的大小,list执行扩容的机会很多。而且感觉修改后代码的逻辑并没有复杂化,等有时间搞个压力测试,看看性能的提升。
1 楼 bambooman 2015-03-12  
难有显著提高,反而把代码逻辑搞复杂了。
1、System.arraycopy 本身效率很高,多复制一次差不到哪里去

2、确保容量的扩容操作很少能得到执行。 因为每次扩容大约为 50%。 参见
int newCapacity = (oldCapacity * 3)/2 + 1; 

相关推荐

    ArrayList扩容机制源码解析.md

    本资源根据个人学习和总结,主要介绍Java中ArrayList扩容机制源码的解析,主要包含文字和代码等内容,以源码的形式进行分析,详细介绍了ArrayList扩容机制的整个流程,特此将该资源分享

    Java ArrayList扩容问题实例详解

    "Java ArrayList扩容问题实例详解" Java ArrayList扩容问题实例详解是Java编程语言中一个非常重要的知识点。ArrayList是Java中最常用的集合类之一,它提供了动态数组的功能,可以存储大量的数据。但是,ArrayList在...

    Arraylist扩容原理走读.png

    Arraylist扩容原理走读

    ArrayList集合与HashMap的扩容原来.docx

    ArrayList扩容原理 ArrayList集合的底层是数组,特点是查询快增删慢。当创建一个集合时,ArrayList集合的空参构造底层数组默认长度为 0,即new Object[0]。当添加第一个元素时,掉用了ArrayList集合的add(E e)方法...

    Java中Arraylist动态扩容方法详解

    `grow(minCapacity)`是ArrayList扩容的核心方法,它会计算新的容量大小,通常是旧容量的1.5倍加上2。这样做的目的是为了平衡插入元素的成本和空间浪费。例如,如果当前容量是10,当需要添加第11个元素时,容量会增加...

    对Java ArrayList的自动扩容机制示例讲解

    对Java ArrayList的自动扩容机制示例讲解 在Java中,ArrayList是最常用的集合类之一,它提供了动态扩容的功能,能够自动地根据添加元素的数量来调整内部数组的大小,以满足元素的存储需求。今天,我们将深入探讨...

    ArrayList及HashMap的扩容规则讲解

    通过了解它们的扩容规则,我们可以更好地使用这些数据结构,避免常见的错误和问题。 ArrayList及HashMap的扩容规则是Java编程中非常重要的概念,了解它们的工作机制可以帮助我们编写出更加高效和可靠的代码。

    数组的扩容和链表结构.zip

    Java中的ArrayList类就是基于动态数组实现的,它在扩容时会创建一个新的更大容量的数组,然后将原有元素复制到新数组中。这个过程的时间复杂度为O(n),其中n为原数组的元素数量。因此,频繁的扩容操作会带来性能开销...

    聊一聊jdk1.8中的ArrayList 底层数组是如何扩容的

    JDK 1.8 中 ArrayList 底层数组的扩容机制 在 Java 语言中,ArrayList 是一个非常常用的集合类,它的底层实现是一个动态扩容的数组。当我们向 ArrayList 中添加元素时,如果数组的容量不足以容纳所添加的元素,那么...

    ArrayList源码Jdk1.8

    - **扩容策略**: `ArrayList`的扩容策略不是固定的,但添加元素的操作具有常数级别的平均时间复杂度。 #### 内部实现 1. **基础结构**: - `ArrayList`内部通过一个`Object[]`数组`elementData`来存储数据。 - ...

    ArrayList的实现原理

    为了减少频繁的扩容操作,可以在创建ArrayList时指定初始容量或在添加大量元素前使用`ensureCapacity`方法预先扩大容量。 - **线程安全**:ArrayList的实现不是线程安全的,意味着在多线程环境下,如果不进行外部...

    Java 实例 - 数组扩容源代码-详细设计教程.zip

    - 如果对数组的动态大小调整有较高需求,可以考虑使用ArrayList代替原始数组,ArrayList在底层实现了动态扩容机制,对开发者来说更便捷。 6. 内存管理: - 扩容后,旧数组不会立即被垃圾回收,只有当所有引用都...

    Java使用数组实现ArrayList的动态扩容的方法

    "Java使用数组实现ArrayList的动态扩容的方法" Java中的ArrayList是使用数组实现的,但是数组有一个缺点,就是在创建时就确定了长度,之后就不能更改长度。因此,Java官方提供了ArrayList这个可变长的容器。...

    ArrayList源码分析

    - 预估容量:在创建ArrayList时,根据预期的元素数量预设容量,可以减少扩容次数,提高性能。 - 尽量避免在循环中调用`add()`或`remove()`,因为这可能导致多次扩容或元素移动。 10. **异常处理** ArrayList的...

    深入Java集合学习系列(三):ArrayList实现原理

    ArrayList基于动态数组的数据结构,因此它能够提供自动扩容的功能,同时也能够快速地进行随机访问。本篇文档将深入探讨ArrayList的内部实现原理。 首先,ArrayList是Java集合框架中List接口的一个非常重要的实现。...

    ArrayList类操作程序实例

    ArrayList是一个基于数组实现的动态列表,可以存储任何类型的数据,并且支持动态扩容。在本实例中,我们将深入探讨ArrayList的常用操作、特性和注意事项。 一、ArrayList的构造方法 ArrayList提供了几种构造方法,...

    超详细JDK1.8 ArrayList集合默认长度及扩容分析

    这个方法是ArrayList扩容的核心,它的目标是确保数组的容量至少等于`minCapacity`: ```java private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { ...

    深入Java集合学习系列:ArrayList的实现原理

    当我们向ArrayList中添加元素时,如果当前数组已满,ArrayList会自动扩容。扩容的策略通常是将当前容量翻倍,以减少频繁扩容带来的性能开销。这个过程涉及到数组的复制,是ArrayList的一个重要性能考虑点。 ...

    C语言版的ArrayList

    C语言版的ArrayList,具有ArrayList的基本方法增加、插入、删除、自动扩容等。

    ArrayList集合工具类

    通过查看源代码,我们可以学习到如何在JavaScript环境中模拟ArrayList的行为,以及如何处理与Java中的ArrayList不同的问题,如线程安全和动态扩容等。 总的来说,ArrayList集合工具类是Java编程中的核心组件,它在...

Global site tag (gtag.js) - Google Analytics