一、 数据代码结构----跟链表(LinkList)是不同的结构
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// 版本号
private static final long serialVersionUID = 8683452581122892189L;
// 缺省容量
private static final int DEFAULT_CAPACITY = 10;
// 空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素数组
transient Object[] elementData;
// 实际元素大小,默认为0
private int size;
// 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* 无参构造方法
* 亲自尝试 List<T> list=new ArrayList<>() 时会走这,构造【缺省空对象数组】
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 带参数的构造方法
* 亲自尝试 List<T> list=new ArrayList<>(7) 时会走这
*/
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);
}
}
/**
* Collection<T>类型构造方法
* 亲自尝试 Collection<MyClass> myCollection;
* ArrayList<MyClass> myList = new ArrayList<MyClass>(myCollection);
* 时会走这,但这种构造方法不常用
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
}
二、线程安全
对ArrayList进行添加元素的操作的时候是分两个步骤进行的,
第一步:先在object[size]的位置上存放需要添加的元素;
第二步:将size的值增加1。
由于这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。
如果非要在多线程的环境下使用ArrayList,就需要保证它的线程安全性,通常有两种解决办法:第一,使用synchronized关键字;第二,可以用Collections类中的静态方法synchronizedList(); 对ArrayList进行调用即可。三,CopyOnWriteArrayList这是一个ArrayList的线程安全的变体;
List<String> list = Collections.synchronizedList(new ArrayList<String>());
list.add("1");
list.add("2");
list.add("3");
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext()) {
//foo(i.next());
System.out.println(i.next());
}
}
三、继承关系
ArrayList 继承 AbstractList抽象父类,实现了List接口(规定了List的操作规范)、RandomAccess(可随机访问)、Cloneable(可拷贝)、Serializable(可序列化)
四、扩容机制
add() ----> ensureCapacityInternal(确保内部容量) ----> ensureExplicitCapacity(确保明确的容量) ----> grow(增长) ----> hugeCapacity(若超过最大,返回最大)
五、set 方法,get 方法,index of 方法,remove 方法,add方法(看上面)
set:1. 先判断索引是否合法;2. 如果所引致合法,将索引对应的oldValue取出;3. 将索引指向 newValue;4. 返回oldValue;
get: 1. 判断索引是否合法; 2. 如果所引致合法,则调用elementData(int index)方法获取值
remove:1.判断索引是否合法;2. 将指定下标后面一位到数组末尾的全部元素向前移动一个单位,并且把数组最后一个元素设置为null;
这样方便之后将整个数组不再使用时,会被GC,可以作为小技巧。而需要移动的元素个数为:size-index-1。
String[] s1 = {"中国","山西","太原","TYUT","zyy","加拿大","不知道哪个州","不知道哪个市","不知道哪个学校","yxf"}; String[] s2 = new String[10]; System.arraycopy(s1, 1, s2, 0, 8); 把s1集合从下标1开始进行拷贝,拷贝到s2集合里index位置,拷贝的数据长度为8;
indexOf:从头开始查找与指定元素相等的元素,如果找到,则返回找到的元素在元素数组中的下标,如果没有找到返回-1;
1. 判断查找的元素是否为空; 2. 不为空直接循环遍历元素数组,通过equals方法来判断对象是否相同,相同就返回下标,找不到就返回-1;
判断空对象的原因是:若为空调用equals方法则会产生空指针异常
复制数组另一方法:Arrays.copyOf(array, to_index);