0.List
- List是Collection的子接口,
public interface List<E> extends Collection<E>
,该接口依然使用了泛型技术 - List里面的所有内容是允许重复的
- 有序集合(也称为序列 )
- 该接口可以精确控制列表中每个元素的插入位置。
- 可以通过整数索引(列表中的位置)访问元素
List接口常用的实现类有如下:
ArrayList、Vector、LinkedList,其中ArrayList和Vector都是基于动态数组的实现,LinkedList是基于链表
1.ArrayList
ArrayList基于数组,动态扩容,增删慢,查找快,
其中的属性包括如下:
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; // non-private to simplify nested class access
private int size; //所存储数据的个数而非容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}
1.1 构造方法
-
ArrayList() 创建一个初始容量为10的空列表
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
是一个长度为0的Object[],但为什么默认容量为10 ?因为在第一次使用时由于为容量为0,所以必定会扩容,而第一次扩容的长度为DEFAULT_CAPACITY -
ArrayList(int initialCapacity) 创建一个初始容量为initialCapacity的空列表
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); } }
initialCapacity为负数时会报错
-
ArrayList(Collection<? extends E> c) 按照集合迭代器返回的顺序构造包含指定集合元素的列表
public ArrayList(Collection<? extends E> c) { Object[] a = c.toArray(); if ((size = a.length) != 0) { if (c.getClass() == ArrayList.class) { elementData = a; } else { elementData = Arrays.copyOf(a, size, Object[].class); // ??? } } else { // replace with empty array. elementData = EMPTY_ELEMENTDATA; } }
1.2添加元素(扩容)
当添加元素时,如果元素数量大于容量,则会发生扩容,容量增加到原来的1.5倍,部分源码实现;
public boolean add(E e) { //添加一个元素到末尾
modCount++;
add(e, elementData, size);
return true;
}
public boolean addAll(Collection<? extends E> c) {//添加Collection的所有元素
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
System.arraycopy(a, 0, elementData, s, numNew);
size = s + numNew;
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow(); //扩容,当size等于elementData的容量时,此时再添加元素会先扩容
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
return grow(size + 1);
}
private Object[] grow(int minCapacity) { // minCapacity = size + 1;即容量最少加1
//根据旧数组和新长度copy一个新数组,并将旧数组指向这个新数组;
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //增加旧容量的的0.5倍,即扩容1.5倍
if (newCapacity - minCapacity <= 0) { //1.5倍扩容后,仍不满足或刚好满足容量最少加1
//为空时,当第一次使用一个空的ArrayList时,会扩容DEFAULT_CAPACITY=10个容量
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
// private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
- 为什要使用
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
而不直接使用Integer.MAX_VALUE
?
。。。 - 删除元素时是否会导致容量减少?
不会自动减少,但可以用trimToSize(),将此ArrayList
实例的容量调整为列表的当前大小。。
1.3其他操作
public void add (int index, E element) //将指定元素插入此列表中的指定位置。
public boolean add (E e) //将指定的元素追加到此列表的末尾。
public boolean addAll (int index, Collection<? extends E> c) //从指定位置开始,将指定集合中的所有元素插入此列表。
public boolean addAll (Collection<? extends E> c) //将指定集合中的所有元素按指定集合的Iterator返回的顺序附加到此列表的末尾。
public E remove(int index) //删除并返回对应下标的元素
public boolean remove(Object o) //删除指定元素
public boolean removeAll (Collection<?> c) //从此列表中删除指定集合中包含的所有元素。
public boolean retainAll (Collection<?> c) //仅保留此列表中包含在指定集合中的元素。
public void clear(){} //将所有元素置为null
public E get (int index) //返回此列表中指定位置的元素。
public int indexOf (Object o) //返回列表中第一次出现指定元素的索引,如果不包含该元素,返回-1。
public int lastIndexOf (Object o) //返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回-1。
public boolean contains (Object o) //如果此列表包含指定的元素,则返回 true
public List<E> subList (int fromIndex, int toIndex) //返回fromIndex(包含)和toIndex(不包括)之间的元素。
public boolean isEmpty() //如果此列表不包含任何元素,则返回 true
public E set (int index, E element) //用指定的元素替换此列表中指定位置的元素。
public int size() //返回此列表中的元素数,即返回size。
public Iterator<E> iterator() //以适当的顺序返回此列表中元素的迭代器。
forEach用法
public void trimToSize() //将此 ArrayList实例的容量调整为列表的当前大小。
public Object clone() //返回此ArrayList实例的浅拷贝。
//该clone()方法并不是ArrayList类中特定的方法。任何继承了CLonable接口的类都能够使用
- 深浅拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存, 所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
浅拷贝对应的就是深拷贝,深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
2.LinkedList
-
LinkedList是双向链表结构,增删快,查找慢
-
LinkedList 基于链表,故除List接口中的方法之外,还可以模拟实现栈、队列、双端队列的等数据结构的操作
变量和类型 | 方法 | 描述 |
---|---|---|
void | addFirst(E e) | 在此列表的开头插入指定的元素。 |
void | addLast(E e) | 将指定的元素追加到此列表的末尾。 |
E | remove() | 检索并删除此列表的头部(第一个元素)。 |
E | removeFirst() | 从此列表中删除并返回第一个元素。 |
boolean | removeFirstOccurrence(Object o) | 删除此列表中第一次出现的指定元素(从头到尾遍历列表时)。 |
E | removeLast() | 从此列表中删除并返回最后一个元素。 |
boolean | removeLastOccurrence(Object o) | 删除此列表中最后一次出现的指定元素(从头到尾遍历列表时)。 |
E | get(int index) | 返回此列表中指定位置的元素。 |
E | getFirst() | 返回此列表中的第一个元素。 |
E | getLast() | 返回此列表中的最后一个元素。 |
boolean | offer(E e) | 将指定的元素添加为此列表的尾部(最后一个元素)。 |
boolean | offerFirst(E e) | 在此列表的前面插入指定的元素。 |
boolean | offerLast(E e) | 在此列表的末尾插入指定的元素。 |
E | pop() | 弹出此列表所代表的堆栈中的元素,即弹出最后一个元素 |
void | push(E e) | 将元素推送到此列表所表示的堆栈上, 即将元素添加到末尾 |
3.Vector
- Vector相比于ArrayList是线程安全的,如果不需要线程安全实现,建议使用ArrayList代替
Vector
- Vector在新建对象时可以指定扩容增量
构造器 | 描述 |
---|---|
Vector() | 构造一个空向量,使其内部数据数组的大小为 10 ,其标准容量增量为零。 |
Vector(int initialCapacity) | 构造一个具有指定初始容量且容量增量等于零的空向量。 |
Vector(int initialCapacity, int capacityIncrement) | 构造具有指定初始容量和容量增量的空向量。 |
Vector(Collection<? extends E> c) | 按照集合的迭代器返回的顺序构造一个包含指定集合元素的向量。 |
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容增量如果大于零,则增加对应的容量,否则容量翻倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity <= 0) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}