当前位置:网站首页>ArrayList源码解析
ArrayList源码解析
2022-07-21 17:35:00 【卷王中王】
1.ArrayList继承关系
2. ArrayList类成员变量
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* Default initial capacity. 默认初始化存储容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added. 空参构造器创建的对象
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial 数组存储的元素个数
*/
private int size;
3. ArrayList构造器
3.1 无参构造器
会把成员变量的空数组赋值。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
3.2 带有初始容量的构造器
- 如果设置的参数大于0,就会创建指定大小容量的object数组。如果为0,赋值为空数组。否则出现异常。
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
3.3 带有集合参数的构造器
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
4. ArrayList方法解析
4.1 add方法解析
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
4.2 get方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
5. ArrayList扩容
第一次扩容容量变为10.
后续扩容每次扩容为前一次的1.5倍(oldCapacity + (oldCapacity >> 1))。
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);
}
6.ArrayList相关知识点
思考一:ArrayList如何扩容的? (参考第五节)
思考二:ArrayList频繁扩容会造成性能急剧下降,如何让解决?
答:可以通过创建ArrayList时指定数组的容量,减少扩容次数。
思考三:ArrayList插入和删除元素一定比LinkedList慢吗?
答:不一定慢。
以删除为例:
在ArrayList底层删除元素,首先根据数组下标索引找到元素,然后把索引后面是所有数据进行前移。
在LinkedList底层使用双向链表,删除元素,首先根据下标索引,判断是从头遍历链表还是从尾部遍历链表,然后在遍历链表,找到相关节点,然后改变节点前后节点的指针索引。
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* Removes and returns the last element from this list.
*
* @return the last element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
/**
* Unlinks non-null last node l.
*/
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
思考四:ArrayList是线程安全的吗?
答:不是线程安全的。
解决方法:
- 使用Vector类
- 使用Collections.synchronizedList() 转换list集合
- 使用CopyOnWriteArrayList,这个使用了读写分离的思想,写时复制,牺牲数据实时性,换取数据最终一致性。上面两种方式通过synchronized的方式,在读写时都会加锁,效率较低。这种方式效率较高,但是底层会进行内存占用过大。
cow原理:
Object[] elements;
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
setArray(elements);
思考五:怎么实现从一个ArrayList复制到另一个ArrayList?
答:
- clone()
- new ArrayList(list)
- addAll(list);
思考六:ArrayList和LinkedList的区别?
边栏推荐
- openlayers 使用canvas绘制圆形头像图标
- Document operation II (5000 word summary)
- La Fondation n'est pas assez solide pour secouer la montagne
- Solve the problem that the plug-in center of idea is not connected to the network
- 自定义图片裁剪框
- Remove styles pasted in TinyMCE
- 自定义View——点击冒泡效果
- Hisilicon hi3531 | Ruixin micro rk1109 realizes H264 streaming with RTSP client
- [Samsung 6818] GPIO analog SPI signal writing access card identification module driver
- Hisilicon [hi3531] onvif+gosap auto search IP_ Implementation of discovery and PTZ
猜你喜欢
【OAuth2】二、OAuth2的授权方式
Quantitative transaction Diary - summary in January 2021
Solve the problem that the plug-in center of idea is not connected to the network
OSPF republish
科创人·观远数据CEO苏春园:让业务用起来,是BI行业推倒渗透率之墙的关键
Cannot read property ‘type‘ of undefined Occurred while linting **\index. jsx:1
Commonly used instructions in RT thread
5G和移动边缘计算服务器如何打造智慧园区
Formation and destruction of function stack frames (26 pictures help you understand function stack frames in depth)
Two methods of redis installation and configuration in Windows Environment
随机推荐
2.4. 特殊概要文件的属性
[C language] document operation "I"
Cannot read property ‘type‘ of undefined Occurred while linting **\index. jsx:1
2021-09-23
Commonly used instructions in RT thread
Quantify three types of market in trading
v-7
RT-Thread中常用的指令
Hisilicon [hi3531]gpio lighting application and register operation
Weak foundation, shaking earth and mountains, Niu Ke brushes the title "II"
Openlayers uses canvas to draw round avatar icons
JS object deep copy
Must use destructuring props assignmenteslint
Pointer depth solution "II" (pointer points to itself)
js判断是否为整数
Pointer depth solution "three" (array cognition)
2022年华泰开户网上办理安全吗?
一篇让理解你Mysql存储引擎
文件操作以及相关函数
IO 模型详解(通俗易懂)