ArrayList底层实现
ArrayList 底层是有数组实现,实际上存放的是对象的引用,而不是对象本身。当使用不带参的构造方法生成ArrayList对象时,实际会在底层生成一个长度为10的数组
当添加元素超过10的时候,会进行扩容 基本上是原来的1.5倍 oldlenth+(oldlenth>>1) 1.5oldlength
>> 表示右移 10>>1(000 1010)右移一位为 5(000 0101)
我们来看下源码
ArrayList a = new ArrayList(); 新建一个arraylist 点进去会出现
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
头说明非常清楚,创建一个空的list,初始化他的长度
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10; /**
* Shared empty array instance used for empty instances.
*/
private static final Object[] 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 == EMPTY_ELEMENTDATA will be expanded to
* DEFAULT_CAPACITY when the first element is added.
*/
private transient Object[] elementData;
DeFAULT_CAPACITY:是某认的长度10
EMPTY_ELEMENTDATA:是list底层实现的数组
transient Object[] elementData:存储数组元素的缓冲区,arraylist的容量是这个数组的长度,任何arraylist与elementData=EMPTY_ELEMENTDATA将会被扩展到添加第一个元素时的DEFAULT_CAPACITY
transient关键字 修饰 表示在序列化的时候,被修饰的不会被序列化。
但是在arraylist中不是这样的,arraylist实现了序列化的writeObject()可指定序列化,arrayList将强制把elementData序列化,但是arryaList内部序列化的时候,因为初始
容量有10 ,但是我可能只有5个元素,那么剩下的就会是空值,在序列化的时候会把空值序列化进去,那么就没有意义,如果直接标记序列化则会把空值序列化进去,用transient修饰后然后重写writeObject()方法将其序列化,只序列化存储元素而不是整个数组,这样可以降低序列化的传输量,从而来提示速度
/**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject(); // Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size); // Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
} if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
这里会去根据size的长度去遍历,然后将对应值取出来序列化
boolean add方法 是将改对象加入到数据的最末端
而void add(int index,E element)方法则是要从指定位置+1开始往后使用arraycopy方法赋值数组操作,之后在对对应元素赋值
void add方法
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
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++;
}
boolean add方法
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
我们来一句一句的分析
进入add方法首先就是ensureCapacityInternal(size+1)设置内部缓冲区,在当前基础上+1,然后将元素添加到数组中
ensureCapacity()方法
首先会判断数组对象是不是初始化数组,如果是的话,则会用初始化值也就是默认的长度10和我们现在传给他的长度做对比
如果传给他的值大于10则minCapacity最小容量为传的值,反之则为10.然后去设置缓冲区大小进入 ensureExplicitCapacity(minCapacity);
ensureExplicitCapacity(minCapacity)
首先 modCount会自增,然后判断传过来的最知晓容量是否大于现有数组的长度,如果大于则扩容进入grow(minCapacity)方法
gorw(minCapacity)
方法中,会想当前数组的长度基础上右移一位然后加上当前数组的长度相当于1.5倍,然后用新得到的长度和最小容量去对比
如果小于最小容量,则新容量为最小容量,反正则不变。然后新容量会和list最大长度对比,如果他比list最大值还大则返回默认定义的MAX_VALUE
最后调用copy方法进行赋值
本文初次读源码。。里面可能会有很多错误或者意思描述不清的地方,希望大家指出来,我好改正以免误导别人。。。大家一起共同学习进步
ArrayList底层实现的更多相关文章
- ArrayList底层原理
ArrayList底层采用数组实现,访问特别快,它可以根据索引下标快速找到元素.但添加插入删除等写操作效率低,因为涉及到内存数据复制转移. ArrayList对象初始化时,无参数构造器默认容量为10, ...
- 模拟ArrayList底层实现
package chengbaoDemo; import java.util.ArrayList; import java.util.Arrays; import comman.Human; /** ...
- ArrayList底层实现原理
ArrayList概述: ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.除了实现列表接口外,此类还提供一些方法来操作内部用来存储列表的数组 ...
- ArrayList 底层实现原理
ArrayList的底层实现原理 1, 属性:private static final int DEFAULT_CAPACITY = 10; private static final Object [ ...
- JAVA SE ArrayList 底层实现
Array 查询效率高,增删效率低( Link 增删效率高 Vector 线程安全 List 列表 源代码: package com.littlepage.test; /** * 基于底层实现Arra ...
- Java——ArrayList底层源码分析
1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数 ...
- ArrayList底层代码解析笔记
通过底层代码可以学习到很多东西: public class ArrayList<E> extends AbstractList<E> implements List<E& ...
- Java ArrayList底层实现原理源码详细分析Jdk8
简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用 ...
- ArrayList、LinkedList、HashMap底层实现
ArrayList 底层的实现就是一个数组(固定大小),当数组长度不够用的时候就会重新开辟一个新的数组,然后将原来的数据拷贝到新的数组内. LinkedList 底层是一个链表,是由java实现的一个 ...
随机推荐
- 【mysql】排序方法
查询各科成绩前三名的记录,不考虑并列的情况: select a.course_id as 课程ID, a.score as 成绩, count(a.course_id) as 排名 from scor ...
- 深入浅出js中的this
Q:this是什么? A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者 ...
- 接口测试之基础篇--http协议
概念:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准.设计HTTP最初的目的是为了提供一种 ...
- PowerDesigner中翻转生成PDM图时把Name属性变成注释(转)
在pd里面运行下面这段代码'******************************************************************************'* File: ...
- 通过ftp同步服务器文件:遍历文件夹所有文件(含子文件夹、进度条);简单http同步服务器文件实例
该代码主要实现,指定ftp服务地址,遍历下载该地址下所有文件(含子文件夹下文件),并提供进度条显示:另外附带有通过http地址方式获取服务器文件的简单实例 废话不多说,直接上代码: 1.FTPHelp ...
- Revit开发小技巧——撤销操作
最近开发Revit命令需要限制某些操作,思路是监控用户操作,如果达到限制条件,将操作回退.思路有两种: 1.调用WindowsAPI,发送快捷命令Ctrl+Z. 2.通过Revit底层提供DLL找到回 ...
- Python 函数修饰符(装饰器)的使用
Python 函数修饰符(装饰器)的使用 1. 修饰符的来源修饰符是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等. 修饰符是解决这类问题的绝佳设计, ...
- Python获取每一位的数字,并返回到列表
通过计算 def calc(value): result = [] while value: result.append(value % 10) value = value // 10 #逆序,按正常 ...
- 利用workbench对linux/Ubuntu系统中的mysql数据库进行操作
在上一篇文章中,我分享了在linux中如何安装mysql数据库,但是这只是安装了mysql的服务,并没有图形化管理界面,所以这样子操作起来并没有那么方便,那么现在我们就来实现如何利用在window中安 ...
- 1.21 贪心入门上午PAT例题题解
1.B1023 #include<cstdio> int a[10]; int main() { for(int i=0;i<=9;i++) { scanf("%d&quo ...