博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ArrayList 原理(2)
阅读量:6296 次
发布时间:2019-06-22

本文共 3008 字,大约阅读时间需要 10 分钟。

1. 概述

中是这样描述的:

以数组实现。节约空间,但数组有容量限制。超出限制时会增加50%容量,用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值。默认第一次插入元素时创建大小为10的数组。

按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。

直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。

然后再来学习一下官方文档:

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

ArrayList是一个相对来说比较简单的数据结构,最重要的一点就是它的自动扩容,可以认为就是我们常说的“动态数组”。

来看一段简单的代码:

1
2
3
4
5
ArrayList<String> list =
new
ArrayList<String>();
list.add(
"语文: 99"
);
list.add(
"数学: 98"
);
list.add(
"英语: 100"
);
list.remove(
0
);

在执行这四条语句时,是这么变化的:

其中,add操作可以理解为直接将数组的内容置位,remove操作可以理解为删除index为0的节点,并将后面元素移到0处。

2. add函数

当我们在ArrayList中增加元素的时候,会使用add函数。他会将元素放到末尾。具体实现如下:

1
2
3
4
5
public
boolean
add(E e) {
    
ensureCapacityInternal(size +
1
); 
// Increments modCount!!
    
elementData[size++] = e;
    
return
true
;
}

我们可以看到他的实现其实最核心的内容就是ensureCapacityInternal。这个函数其实就是自动扩容机制的核心。我们依次来看一下他的具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private
void
ensureCapacityInternal(
int
minCapacity) {
    
if
(elementData == DEFAULTCAPACITY_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);
}
 
private
void
grow(
int
minCapacity) {
    
// overflow-conscious code
    
int
oldCapacity = elementData.length;
    
// 扩展为原来的1.5倍
    
int
newCapacity = oldCapacity + (oldCapacity >>
1
);
    
// 如果扩为1.5倍还不满足需求,直接扩为需求值
    
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);
}

也就是说,当增加数据的时候,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的操作就是把老的数组拷到新的数组里面。例如,默认的数组大小是10,也就是说当我们add10个元素之后,再进行一次add时,就会发生自动扩容,数组长度由10变为了15具体情况如下所示:

3 set和get函数

Array的put和get函数就比较简单了,先做index检查,然后执行赋值或访问操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
public
E set(
int
index, E element) {
    
rangeCheck(index);
 
    
E oldValue = elementData(index);
    
elementData[index] = element;
    
return
oldValue;
}
 
public
E get(
int
index) {
    
rangeCheck(index);
 
    
return
elementData(index);
}

4 remove函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public
E remove(
int
index) {
    
rangeCheck(index);
 
    
modCount++;
    
E oldValue = elementData(index);
 
    
int
numMoved = size - index -
1
;
    
if
(numMoved >
0
)
        
// 把后面的往前移
        
System.arraycopy(elementData, index+
1
, elementData, index,
                         
numMoved);
    
// 把最后的置null
    
elementData[--size] =
null
;
// clear to let GC do its work
 
    
return
oldValue;
}

注释很清楚:

转载于:https://www.cnblogs.com/maohuidong/p/7965705.html

你可能感兴趣的文章
正文提取算法
查看>>
轻松学PHP
查看>>
Linux中的网络监控命令
查看>>
this的用法
查看>>
windows下安装redis
查看>>
CentOS7 yum 安装git
查看>>
启动日志中频繁出现以下信息
查看>>
httpd – 对Apache的DFOREGROUND感到困惑
查看>>
分布式锁的一点理解
查看>>
idea的maven项目,install下载重复下载本地库中已有的jar包,而且下载后jar包都是lastupdated问题...
查看>>
2019测试指南-web应用程序安全测试(二)指纹Web服务器
查看>>
树莓派3链接wifi
查看>>
js面向对象编程
查看>>
Ruby中类 模块 单例方法 总结
查看>>
jQuery的validate插件
查看>>
5-4 8 管道符 作业控制 shell变量 环境变量配置
查看>>
Enumberable
查看>>
开发者论坛一周精粹(第五十四期) 求购备案服务号1枚!
查看>>
validate表单验证及自定义方法
查看>>
javascript 中出现missing ) after argument list的错误
查看>>