前言:
什么是容器
:容器就好像一个存放对象的仓库,可以将你的东西存放在一个无限制的仓库中,然后要用的时候可以取出来
接口List
List接口是继承Collection接口
他常用的实现类:ArrayList、linkedList、Vector
List接口方法
void add(E element)
在末尾添加元素。
void add(int index, E element)
在指定位置插入元素,后面的元素都往后移一个元素。
boolean addAll(int index, Collection<? extends E> c)
在指定的位置中插入c集合全部的元素,如果集合发生改变,则返回true,否则返回false。
E get(int index)
返回list集合中指定索引位置的元素
int indexOf(Object o)
返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1
ListIterator<E> listIterator()
返回此列表元素的列表迭代器
ListIterator<E> listIterator(int index)
从指定位置开始,返回此列表元素的列表迭代器。
E remove(int index)
删除指定索引的对象
E set(int index, E element)
在索引为index位置的元素更改为element元素
List<E> subList(int fromIndex, int toIndex)
返回从索引[fromIndex,toIndex)的元素集合,包左不包右
ArrayList
ArrayList特点:本质是数组,他是基于数组封装的一个容器 ,所以他是查询快、有序列的、增删慢。
//遍历ArrayList方法
public class arrayList01{
public static void main(String []args){
List<Integer> list=new ArrayList<Integer>();
//使用List接口的方法添加元素
list.add(1);
……
……
for(int every:list){
System.out.print(every+"\t")
}
}
}
ArrayList的动态扩容
上面我们说了ArrayList本质是数组,那么它是如何实现数组的动态扩容的让我们一起来分析源码,首先我们先看ArrayList无参构造器都干了什么。以下是ArrayList无参构造器的源码:
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
此时我们可以看到elementData变量以及DEFAULTCAPACITY_EMPTY_ELEMENTDATA常量,我们看看这两个是什么
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
DEFAULTCAPACITY_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 = {};
那么就可以说使用无参构造器创建的ArrayList集合就是一个空的长度为0的集合
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
那么它又是怎么进行动态扩容的?我们来看它add(E e)方法
-
size : ArrayList 大小(包含元素个数)
-
elementData 上面介绍过的数组缓冲区
-
modCount++;记录集合的操作次数,继承自abstractList.
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
有上面代码可见add(E e)方法又调用了它的重载函数add(e, elementData, size); 我们继续深入查看
- if (s == elementData.length)它先是做了一个判断,查看当前集合元素个数是否和数组缓冲区大小相等,如果相等调用grow()方法否则添加这个元素
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
grow()调用了它的重载方法
private Object[] grow() {
return grow(size + 1);
}
动态扩容的本质
- DEFAULT_CAPACITY=10:默认容量为10
- minCapacity:size+1
-
oldCapacity:数组缓冲区的长度
-
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 判断数组缓冲区的长度是否大于0; 数组缓冲区是否不等于使用无参构造器创建ArrayList时赋值的默认空数组。
简单理解这个就是判断这个集合是否是第一次使用的
/**
* 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
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
//如果不是第一次使用则判断使用ArraysSupport.newLength(int oldLength, int minGrowth, int prefGrowth)判断容量增长的长度,然后返回的复制数组
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
}
//如果是第一次使用数组让elementData数组缓冲区等于一个新的数组并返回,其数组长度等于size+1>10 ? size+1:10;
else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
LinkedList
LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用.