Java ArrayList 源码分析与提高性能替代方案
2017-09-25 17:04
453 查看
自娱自乐,不喜莫喷。目前还是大三狗,错误很多,望大神指正。
看同学java一用到list全部是ArrayList,但是ArrayList真的万能吗?顾名思义Array==数组,添加,删除肯定要有扩张,收缩操作,会拖慢性能,对于常读的自然没关系,但是有时做信息缓冲区时,添加、删除频繁,ArrayList肯定不好。
先看结果:
不带index的添加:新建ArrayList时数组大小为0;第一次添加时新建一个大小为10的数组,以后不够用时,每次扩大一半,即:10,15,22。。。每逢这些大小,就重建数组然后把源数据拷过来,这是非常不符合缓冲区的要求的。
带index的添加:数组空间不够时即:数组大小为[u]10,15,22。。。时先[/u]做一次扩张操作,然后再拷贝一次以完成在目标位置添加,拷贝操作最少一次,最多两次。。。喵喵喵???
java.util.concurrent下有许多集合类,你们可以自己看看,我找到的比较好用的:
ArrayList:数组实现,随机查找,随机读操作非常快,写。。。
LinkedList:链表实现,可以快速增删,顺序读取,缺点时随机读取慢,得遍历一遍,单线程时做缓冲区最适合不过
HashSet:没有重复的无序集合(插入重复元素不会理你)
TreeSet:有序集合(红黑树实现)
HashMap:最常用的map类: transient Node<K,V>[] table; 也是数组实现
linkedHashMap:顾名思义,HashMap的链表实现
weakHashMap:不会增加对象的引用计数,所以gc回收时不会考虑它里面的引用
多线程:java.util.concurrent包下有许多多线程支持的工具,不需要自己加锁来控制哦,自带锁机制:
ConcurrentLinkedQueue:多线程安全的 无边界 非阻塞 队列,链表实现,多线程缓冲区首选
ConcurrentSkipListMap:多线程安全的散列表
下面是ArrayList源码分析:
我们最常用的无参构造器:
可以看出真实数据elementData只指向一个已经定义好的是一个空数组,第一次添加时肯定要重新生成array;
最常用的add第一步调用ensureCapacityInternal(size + 1),确保数组有足够的空间:
我们看看ensureCapacityInternal函数:
可以看出正如我们之前所想如果elementData是默认的话,就新建一个数组,数组大小为默认大小和所需扩张后大小之间去最大值
默认大小为:
即10,所以无参ArrayList构造时数组大小为0,第一次添加扩张为10
然后看扩张函数:
用transient声明的实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
modcount只是用来记录数组变化次数的,当它的数据出错时会抛出错误,不过我们不关注,重点是grow函数:
好,这就是我们要找的扩张函数最终实现了:
oldCapacity >> 1 :基本等于oldCapacity/2 取整数部分
所以每次扩张时大小为原来的3/2,即增大一半;
如果满足需求就这样定了,如果不满足,就按需求来;
最后ArrayList最大约束:如果 小,就把原来的数组烤进新数组,最大约束为:
即:int的最大值减8
如果大的话;处理:
哇,欺骗我感情,我还以为会用两个数组之类的重实现,结果就再加8位???喵喵喵???
so,我们得到结果:
添加时,第一次添加新建一个大小为10的数组,以后不够用时,每次扩大一半,即:10,15,22。。。
每逢这些大小,就重建数组然后把源数据拷过来,这是非常不符合缓冲区的要求的。
而带index的添加:
可见不够时做一次扩张操作,然后再拷贝一次,
拷贝操作最少一次,最多两次。。。喵喵喵???
删除就不讲了,和带index的插入差不多
所以当我们把需要一个缓冲区时得用什么呢?
java.util.concurrent下有许多集合类,你们可以自己看看,我找到的比较好用的:
ArrayList:数组实现,随机查找,随机读操作非常快,写。。。
LinkedList:链表实现,可以快速增删,顺序读取,缺点时随机读取慢,得遍历一遍,单线程时做缓冲区最适合不过
HashSet:没有重复的无序集合(插入重复元素不会理你)
TreeSet:有序集合(红黑树实现)
HashMap:最常用的map类: transient Node<K,V>[] table; 也是数组实现
linkedHashMap:顾名思义,HashMap的链表实现
weakHashMap:不会增加对象的引用计数,所以gc回收时不会考虑它里面的引用
多线程:java.util.concurrent包下有许多多线程支持的工具,不需要自己加锁来控制哦,自带锁机制:
ConcurrentLinkedQueue:多线程安全的 无边界 非阻塞 队列,链表实现
ConcurrentSkipListMap:多线程安全的散列表
版权声明:本文为博主原创文章,转载请注明来源:http://blog.csdn.net/qq_33213364
看同学java一用到list全部是ArrayList,但是ArrayList真的万能吗?顾名思义Array==数组,添加,删除肯定要有扩张,收缩操作,会拖慢性能,对于常读的自然没关系,但是有时做信息缓冲区时,添加、删除频繁,ArrayList肯定不好。
先看结果:
不带index的添加:新建ArrayList时数组大小为0;第一次添加时新建一个大小为10的数组,以后不够用时,每次扩大一半,即:10,15,22。。。每逢这些大小,就重建数组然后把源数据拷过来,这是非常不符合缓冲区的要求的。
带index的添加:数组空间不够时即:数组大小为[u]10,15,22。。。时先[/u]做一次扩张操作,然后再拷贝一次以完成在目标位置添加,拷贝操作最少一次,最多两次。。。喵喵喵???
java.util.concurrent下有许多集合类,你们可以自己看看,我找到的比较好用的:
ArrayList:数组实现,随机查找,随机读操作非常快,写。。。
LinkedList:链表实现,可以快速增删,顺序读取,缺点时随机读取慢,得遍历一遍,单线程时做缓冲区最适合不过
HashSet:没有重复的无序集合(插入重复元素不会理你)
TreeSet:有序集合(红黑树实现)
HashMap:最常用的map类: transient Node<K,V>[] table; 也是数组实现
linkedHashMap:顾名思义,HashMap的链表实现
weakHashMap:不会增加对象的引用计数,所以gc回收时不会考虑它里面的引用
多线程:java.util.concurrent包下有许多多线程支持的工具,不需要自己加锁来控制哦,自带锁机制:
ConcurrentLinkedQueue:多线程安全的 无边界 非阻塞 队列,链表实现,多线程缓冲区首选
ConcurrentSkipListMap:多线程安全的散列表
下面是ArrayList源码分析:
我们最常用的无参构造器:
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
可以看出真实数据elementData只指向一个已经定义好的是一个空数组,第一次添加时肯定要重新生成array;
最常用的add第一步调用ensureCapacityInternal(size + 1),确保数组有足够的空间:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
我们看看ensureCapacityInternal函数:
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
可以看出正如我们之前所想如果elementData是默认的话,就新建一个数组,数组大小为默认大小和所需扩张后大小之间去最大值
默认大小为:
private static final int DEFAULT_CAPACITY = 10;
即10,所以无参ArrayList构造时数组大小为0,第一次添加扩张为10
然后看扩张函数:
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
protected transient int modCount = 0;
用transient声明的实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
modcount只是用来记录数组变化次数的,当它的数据出错时会抛出错误,不过我们不关注,重点是grow函数:
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); }
好,这就是我们要找的扩张函数最终实现了:
oldCapacity >> 1 :基本等于oldCapacity/2 取整数部分
所以每次扩张时大小为原来的3/2,即增大一半;
如果满足需求就这样定了,如果不满足,就按需求来;
最后ArrayList最大约束:如果 小,就把原来的数组烤进新数组,最大约束为:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
即:int的最大值减8
如果大的话;处理:
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
哇,欺骗我感情,我还以为会用两个数组之类的重实现,结果就再加8位???喵喵喵???
so,我们得到结果:
添加时,第一次添加新建一个大小为10的数组,以后不够用时,每次扩大一半,即:10,15,22。。。
每逢这些大小,就重建数组然后把源数据拷过来,这是非常不符合缓冲区的要求的。
而带index的添加:
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
可见不够时做一次扩张操作,然后再拷贝一次,
拷贝操作最少一次,最多两次。。。喵喵喵???
删除就不讲了,和带index的插入差不多
所以当我们把需要一个缓冲区时得用什么呢?
java.util.concurrent下有许多集合类,你们可以自己看看,我找到的比较好用的:
ArrayList:数组实现,随机查找,随机读操作非常快,写。。。
LinkedList:链表实现,可以快速增删,顺序读取,缺点时随机读取慢,得遍历一遍,单线程时做缓冲区最适合不过
HashSet:没有重复的无序集合(插入重复元素不会理你)
TreeSet:有序集合(红黑树实现)
HashMap:最常用的map类: transient Node<K,V>[] table; 也是数组实现
linkedHashMap:顾名思义,HashMap的链表实现
weakHashMap:不会增加对象的引用计数,所以gc回收时不会考虑它里面的引用
多线程:java.util.concurrent包下有许多多线程支持的工具,不需要自己加锁来控制哦,自带锁机制:
ConcurrentLinkedQueue:多线程安全的 无边界 非阻塞 队列,链表实现
ConcurrentSkipListMap:多线程安全的散列表
版权声明:本文为博主原创文章,转载请注明来源:http://blog.csdn.net/qq_33213364
相关文章推荐
- java基础提高篇--集合源码分析--jdk1.8 ArrayList源码
- 【Java入门提高篇】Day21 Java容器类详解(四)ArrayList源码分析
- Java中arraylist和linkedlist源码分析与性能比较
- java中Arraylist源码分析扩容过程和性能优化
- JAVA LinkedList和ArrayList的使用及性能分析
- Java使用Arrays、ArrayList、LinkedList、Vector实现插入查询性能分析
- Java 集合系列08之 List总结(LinkedList, ArrayList等使用场景和性能分析)
- [ZT]使用DynamicMethod替代反射,提高100倍的性能!(附源码)
- Java源码分析系列之ArrayList读后感
- Java 集合系列08之 List总结(LinkedList, ArrayList等使用场景和性能分析)
- java 集合ArrayList及LinkList源码分析
- java源码分析之ArrayList
- Java ArrayList源码分析
- (7) java源码分析------之ArrayList (对应数据结构中线性表中的顺序表,JDK1.6)
- Java中ArrayList源码深入分析(JDK1.6)
- java源码分析之ArrayList
- Java源码分析 – ArrayList动态数组列表源码分析
- JDK源码分析之java.util.ArrayList
- java源码分析之ArrayList
- Java集合之ArrayList源码分析