`
yuxuguang
  • 浏览: 136724 次
  • 性别: 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扩容问题实例详解,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下

    Arraylist扩容原理走读.png

    Arraylist扩容原理走读

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

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

    Java中Arraylist动态扩容方法详解

    ArrayList的列表对象实质上是存储在一个引用型数组里的,下面这篇文章主要给大家介绍了关于Java中Arraylist动态扩容方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

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

    今天小编就为大家分享一篇对Java ArrayList的自动扩容机制示例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

    ArrayList及HashMap的扩容规则讲解

    今天小编就为大家分享一篇关于ArrayList及HashMap的扩容规则讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

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

    主要介绍了Java使用数组实现ArrayList的动态扩容的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    C语言版的ArrayList

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

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

    主要介绍了聊一聊jdk1.8中的ArrayList 底层数组是如何扩容的,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

    软通面试题目及面试答案

    软通面试答案,里面有我去软通面试的题目和答案供有需要帮助的朋友提供帮助 14 .关于 ArrayList 答案: ordered no sorttrd 并且是按照 index 排 15- 如何从 ArrayList 里取对象? 用 get(int index) 这个方法。

    Arraylist的一些值得思考的问题

    初始申请的空间与扩容阈值之间的关系,围绕第二次扩容阈值与初始指定申请空间的关系说明 4、模拟写一个新增或删除或扩容的方法 5、是否线程安全?为何不安全?如果不安全如何规避或替代类? 6、for循环数据过程中...

    ArrayList 深入理解底层

    ArrayList Jdk1.8采用的是数组的数据结构,是非线程安全的一个集合 (多线程下数据不安全),本文章主要讲解ArrayList集合添加和集合扩容,其他方法都相对简单,读懂这个后相信你翻翻源码即可读懂其他方法原理,下面...

    C#中的ArrayList导图

     首先,它不是静态的,编译时每一维度的元素个数不用指定,系统默认元素个数为16,当元素增多并即将大于16时,它会增倍扩容到32,依次规律增长,变小时,相反处理。  其次,元素类型是弱类型,object。在运行时,...

    浅谈ArraryList扩容机制

    阅读本文大约需要10分钟,将分成两部分解读ArrayList的扩容机制,源码部分来源于JDK8。 首先,挖个坑:为什么要尽量指定集合大小? 集合初始化 集合初始化有两种方式,直接new,或者在new的时候指定集合大小 List ...

    Java面试题-基础-集合有关的知名厂商面试题和基础复习

    掌握 ArrayList 的扩容机制 掌握 Iterator 的 fail-fast 、fail-safe 机制 ArrayList() 会使用长度为零的数组 ArrayList(int initialCapacity) 会使用指定容量的数组 public ArrayList(Collection&lt;? extends E&gt; c) ...

    ArrayList.md

    老猿说说-ArrayList MD文件 ...4. 除了数组+链表+红黑树的基本结构外,新增了转移节点,是为了保证扩容时的线程安全的节点; 5. 提供了很多Stream流式方法,比如说:forEach、search、reduce等等。

    Java中的ArrayList的底层源码解读、LinkedList、Vector的区别介绍

    适用人群:JavaSE初学者,对源码感兴趣的,想要深度了解ArrayList底层实现、数据结构、add方法、Remove方法、以及自动扩容机制的同学,并且对ArrayList已经有过使用,想要学习它与LinkedList,Vector等的区别,该...

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

    1、首先看ArrayList默认构造方法创建 /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first ...

    shigeqiu#shigeqiu-blog#2_ArrayList与LinkedList1

    ArrayList与LinkedListArrayList与LinkedList扩容数组最大容量默认的初始容量扩容新容量=旧容量*1.5* Increases

Global site tag (gtag.js) - Google Analytics