前言
集合主要是两组(单列集合,双列集合)
Collection 接口有两个重要的子接口 List Set,他们的实现子类都是单列集合
map 接口的实现子类是双列集合 存放的 k-v
一、Collection接口和常用方法
Collection接口常用方法,以实现子类 ArrayList来演示.CollectionMethod.java
1)add:添加单个元素
2) remove:删除指定元素
3)contains:查找元素是否存在
4) size:获取元素个数
5) isEmpty:判断是否为空
6) clear:清空
7) addAll:添加多个元素
8)containsAll:查找多个元素是否都存在
9)removeAll:删除多个元素
10) 说明:以ArrayList实现类来演示.
List接口的常用方法
ListMethod.java
List集合里添加了一些根据索引来操作集合元素的方法
1)void add(int index,Object ele)
:在index位置插入ele元素
2) boolean addAll(int index,Collection eles):
从index位置开始将eles中的所有元素添加进来
3)Object get(int index)
:获取指定index位置的元素
4)int indexOf(Object obj):
返回obj在集合中首次出现的位置
5)int lastlndexOf(Object obj)
:返回obj在当前集合中末次出现的位置
6)Object remove(int index)
:移除指定index位置的元素,并返回此元素
7)Object set(int index,Object ele)
:设置指定index位置的元素为ele,相当于是替换.
8)List subList(int fromlndex,int tolndex)
:返回从fromlndex到tolndex位置的子集合 返回的是前闭后开的集合
ArrayList的注意事项
1)permits all elements,including null ,ArrayList
可以加入null,并且多个
2)ArrayList是由数组来实现数据存储的
3)ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码在多线程情况下,不建议使用ArrayList
ArrayList底层结构和源码分析
1)ArrayList中维护了一个Object类型的数组elementData.[debug 看源码]transient //表示瞬间短暂的表示该属性不会被序列化 Object[] elementData;
2)当创建对象时,如果使用的是无参构造器,则初始elementData容量为0(jdk7是10)
3)当添加元素时:先判断是否需要扩容,如果需要扩容,则调用grow方法,否则直接添加元素到合适位置
4)如果使用的是无参构造器,如果第一次添加,需要扩容的话,则扩容elementData为10,如果需要再次扩容的话,则扩容elementData为1.5倍。
5)如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity
6)如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍
确定是否要扩容
//确定是否要扩容然后再执行赋值操作
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
确定minCapacity方法
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity); //第一次扩容为10
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
判断集合的容量和修改次数
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //用来判断集合被修改的次数 防止多个线程同时修改集合 如果同时修改后抛异常
// overflow-conscious code
if (minCapacity - elementData.length > 0) //判断当前容量是否够
grow(minCapacity); //如果elementData的大小不够的话就调用grow方法去真的扩容
}
集合源码扩容
//使用扩容机制来确定要扩容的多大
//第一次 nweCapacity = 10
//第二次及其以后按照1.5倍
//扩容使用的是Arrays.copyof() 会保留原先数据
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //确定按照1.5倍去扩容
if (newCapacity - minCapacity < 0) //判断扩容后的容量减去最小的容量 还小于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); //将其数组内数据全部赋值为null
}
如果集合使用了有参构造函数的话
//创建一个指定大小的elementData数组
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);
}
}