Java开发使用ArrayList深度解析
程序员文章站
2022-06-27 20:31:20
ArrayList 底层学习底层知识底层使用的是数组的数据结构属性//默认的初始化容量private static final int DEFAULT_CAPACITY = 10;//一个空的Object数组的实例(当使用有参构造器public ArrayList(int initialCapacity)时候自定义容量为0时候赋值给elementData)private static final Object[] EMPTY_ELEMENTDATA = {};//和上面一样是个空数组实例(当...
ArrayList 底层学习
底层知识
底层使用的是数组的数据结构
属性
//默认的初始化容量 private static final int DEFAULT_CAPACITY = 10; //一个空的Object数组的实例(当使用有参构造器public ArrayList(int initialCapacity)时候自定义容量为0时候赋值给elementData) private static final Object[] EMPTY_ELEMENTDATA = {}; //和上面一样是个空数组实例(当使用默认无参构造器时赋值给elementData) private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //真正的存放数组的数组 transient Object[] elementData; //数组的长度 private int size;
构造器
public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity];//如果>0则直接立马给数组分配空间 } else if (initialCapacity == 0) { //如果输入参数为0,那么就赋值一个空数组 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } public ArrayList() { //可在属性中查看 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
从这两个构造器中我们发现,如果我们给它一个整型参数且>0,那么会立马给elementData数组分配空间,如果为0则不管。但是如果调用无参构造器的时候我们发现他并没有分配空间,而是将它指向默认的空的elementData对象,但是并没有立马给他分配空间
newCapacity(int minCapacity)
//这个是将数组进行一个扩容操作, private int newCapacity(int minCapacity) { //保存旧数组的容量 int oldCapacity = elementData.length; //新数组的大小为旧数组+旧数组右移一位的和,相当于是扩大为原来1.5倍(newCapacity为扩容后的容量) int newCapacity = oldCapacity + (oldCapacity >> 1); //下面判断为真的例子 /*
当我们使用默认构造器时候,我们的elementData对象是一个空数组,
那么oldCapacity = elementData.length = 0
那么 newCapacity = oldCapacity + (oldCapacity >> 1) = 0
minCapacity = size + 1 ,此时size = 0,minCapacity = 1
newCapacity - minCapacity = -1 <= 0
*/ if (newCapacity - minCapacity <= 0) { //进入下面的判断分支说明使用的是默认构造器 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) return Math.max(DEFAULT_CAPACITY, minCapacity); // overflow(内存溢出) if (minCapacity < 0) throw new OutOfMemoryError(); //如果使用有参构造器并且自定义capacity定义为0,就会使用下面的return,即返回1 //(非常不建议这样,因为这样会导致数组不停的扩容,影响性能) return minCapacity; } //这是正常的扩容容量, return (newCapacity - MAX_ARRAY_SIZE <= 0) //判断新容量不超过最大容量的三目运算 ? newCapacity //为真 : hugeCapacity(minCapacity); //为假(分析可以看下面) } private static int hugeCapacity(int minCapacity) { //内存已经用完了 if (minCapacity < 0) throw new OutOfMemoryError(); //minCapacity已经超过定义的最大数组长度的三目运算 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE //为真(设置为最大的Int的最大数值容量) : MAX_ARRAY_SIZE; //为假(设置为定义的最大容量) }
add()方法
//这个是扩容时调用的grow方法 private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData,//这里是将旧数组的信息复制到新数组中 newCapacity(minCapacity)); } private Object[] grow() { return grow(size + 1); } private void add(E e, Object[] elementData, int s) { //这里的s传入的基本都是size //当size的长度达到了数组的定义的长度时候就需要会进行扩容 if (s == elementData.length) elementData = grow(); //这里将数据保存进数组中,并且将size + 1 elementData[s] = e; size = s + 1; } //平时调用的最多的方法 public boolean add(E e) { //这个就是继续数组被更改的次数 modCount++; //调用私有方法add Object[] elementData; if ((s = size) == (elementData = this.elementData).length) elementData = grow(); System.arraycopy(elementData, index, elementData, index + 1, s - index); elementData[index] = element; size = s + 1; } //-----------------------------下面为按下标进行一个插入操作--------------------------------------------- private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /*
这个方法我们可以明确的发现
说明:只能插入在list的size以内的数据,相当于只能替换时候使用该方法,平时的插入还是以add(E e)为主
*/ public void add(int index, E element) { //对该下标进行一个判断,看看是否超过size或者index < 0 rangeCheckForAdd(index); //对数组修改操作 + 1 modCount++; final int s; Object[] elementData; //和一个参数的add()方法一样,判断需不需要进行一个扩容操作 if ((s = size) == (elementData = this.elementData).length) elementData = grow(); System.arraycopy(elementData, index, elementData, index + 1, s - index); //将数据存储到数组中 elementData[index] = element; //size + 1 size = s + 1; }
Vector(线程安全)
底层也是使用的暴力加锁方法,直接使用synchronized修饰
如何选择线程安全的集合
1.可以选择线程安全的类,例如Vector,HashTable,ConcurrentHashMap
2.可以使用Collections.synchronized*(),这样的方法
本文地址:https://blog.csdn.net/fxhhh123/article/details/108032853
下一篇: H5页面常见开发问题总结