ArrayList
此类继承了 AbstractList 类。 AbstractList 是 List 接口的子类。 AbstractList 是个抽象类, 适配器设计模式。
采用数组结构存储,增加删除慢,查找快
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
1. 构造方法
- ArrayList() -> 默认初始容量为10,到11个,原10长度会被丢弃,新建15长度(1.5倍扩容),如果需要大量数据,为避免空间浪费,尽量使用下面的含参构造方法。构造时使用的类型要用类,不能使用基本数据类型
ArrayList<Integer> data = new ArrayList<>();
源码如下,DEFAULTCAPACITY_EMPTY_ELEMENTDATA={},所以构造新数组时实际长度是为0的,但文档中初始容量为何为10,这与扩容算法有关
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- ArrayList(int initialCapacity) 构造具有指定初始容量的空列表
- ArrayList(Collection<? extends E> c) 构造一个包含指定集合元素的列表
2. 方法
添加元素
public boolean add(E e)
将指定的元素追加到此列表的末尾。public void add(int index, E element)
将指定元素插入此列表中的指定位置。 将当前位置的元素(如果有)和任何后续元素向右移动(将其添加到索引中)。public boolean addAll(int index, Collection<? extends E> c)
从指定位置开始,将指定集合中的所有元素插入此列表。 将当前位置的元素(如果有)和任何后续元素向右移动(增加其索引)。public boolean addAll(Collection<? extends E> c)
add(E e)源码分析:
public boolean add(E e) {
modCount++;
//add(插入元素,数组数据,有效数据的长度)
add(e, elementData, size);
//无论成功失败都会返回true!!!
return true;
}
private void add(E e, Object[] elementData, int s) {
//如果已有数据量达到数组最大长度,调用grow()扩容算法
if (s == elementData.length)
elementData = grow();
//如果还有空间,直接加到末尾,有效数据长度加1
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
//至少要加1长度
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
//Arrays.copyof()把新长度数组拷贝到原数组
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//oldCapacity >> 1,二进制数右移一位,减小一半,即扩容1.5倍。注意:空数组和1元素的数组扩容无效
int newCapacity = oldCapacity + (oldCapacity >> 1);
//扩容后空间仍然小于最小需要的空间,即不够存
if (newCapacity - minCapacity <= 0) {
//如果原数组为空(即第一次存储),DEFAULTCAPACITY_EMPTY_ELEMENTDATA={},返回DEFAULT_CAPACITY=10和需求的空间的最大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
//最小长度超过int最大值,溢出变成负数,抛出内存溢出异常
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//如果既不是第一次添加数据也没有溢出,即添加一组数据时,如果扩容1.5倍无法满足,则返回最小需要的长度
return minCapacity;
}
//扩容后的新长度够用,且如果小于MAX_ARRAY_SIZE=int最大值-8,返回新长度,不然跳转到hugeCapacity(minCapacity)
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
//首先没有溢出
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//如果所需长度大于int最大值-8
return (minCapacity > MAX_ARRAY_SIZE)
//返回int最大值
? Integer.MAX_VALUE
//不然返回int最大值-8
: MAX_ARRAY_SIZE;
}
使用:
ArrayList<Integer> data = new ArrayList<>();
data.add(100);
data.add(99);
data.add(98);
System.out.println(data.toString());
//[100, 99, 98]
data.add(2,44);
System.out.println(data.toString());
//[100, 99, 44, 98]
ArrayList<Integer> data1 = new ArrayList<>();
data1.add(23);
data1.add(43);
data1.add(56);
data.addAll(2, data1);
System.out.println(data.toString());
//[100, 99, 23, 43, 56, 44, 98]
删除元素
public E remove(int index)
删除此列表中指定位置的元素,并返回该元素。 将任何后续元素向左移位(从索引中减去一个元素)。public boolean remove(Object o)
从该列表中删除指定元素的第一个匹配项(如果存在)。 如果列表不包含该元素,则不会更改。
System.out.println(names.remove(2));
//王五
System.out.println(names);
//[张三, 李四]
System.out.println(names.remove("赵六"));
//false
System.out.println(names.remove("李四"));
//true
System.out.println(names);
//[张三]
public boolean removeIf(Predicate<? super E> filter)
删除此集合中满足给定过滤条件的所有元素。
ArrayList<String> names = new ArrayList<>(3);
names.add("张三");
names.add("李四");
names.add("王五");
System.out.println("Names:"+names);
//Names:[张三, 李四, 王五]
names.removeIf(s -> s.contains("李"));
System.out.println(names);
//[张三, 王五]
ArrayList<Integer> data = new ArrayList<>();
data.add(100);
data.add(99);
data.add(98);
data.add(97);
data.add(96);
data.add(95);
System.out.println(data);
//[100, 99, 98, 97, 96, 95]
//是偶数则删除
data.removeIf(integer -> (integer % 2) == 0);
System.out.println("Odd numbers:" + data);
//Odd numbers:[99, 97, 95]
public boolean removeAll(Collection<?> c)
从此列表中删除指定集合中包含的所有元素。
//data = [100, 99, 98, 97, 96, 95]
//删除指定的数组中的元素
data.removeAll(data);
System.out.println(data);
//[]
protected void removeRange(int fromIndex, int toIndex)
从此列表中删除索引介于fromIndex (含)和toIndex (独占)之间的所有元素。 将任何后续元素向左移动(降低其索引)。 此调用通过(toIndex - fromIndex)元素缩短列表。 (如果toIndex==fromIndex ,此操作无效。)- removeRange() 方法是受保护的(Protected),所以如果要使用需要继承 ArrayList 类,继承后我们就可以使用Demo3类来创建一个动态数组
- 因此使用
ArrayList.subList(int fromIndex, int toIndex).clear()
更方便
public class Demo3 extends ArrayList<Integer>{
public static void main(String[] args) {
Demo3 data = new Demo3();
data.add(100);
data.add(99);
data.add(98);
data.add(97);
data.add(96);
data.add(95);
System.out.println(data);
//[100, 99, 98, 97, 96, 95]
data.removeRange(1, 3);
System.out.println(data);
//[100, 97, 96, 95]
}
}
public boolean retainAll(Collection<?> c)
仅保留此列表中包含在指定集合中的元素。 换句话说,从该列表中删除未包含在指定集合中的所有元素。
//data = [100, 99, 98, 97, 96, 95]
//只保留索引为[2,4)的元素
data.retainAll(data.subList(2,4));
System.out.println(data);
//[98, 97]
public void clear()
//接上
data.clear();
System.out.println(data.toString());
//[]
public Object clone()
- 功能:clone() 方法用于拷贝一份动态数组,属于浅拷贝。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存, 所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
浅拷贝对应的就是深拷贝,深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
data1 = (ArrayList<Integer>)data.clone();
System.out.println(data.clone());
//[100, 99, 23, 43, 56, 44, 98]
System.out.println(data1.toString());
//[100, 99, 23, 43, 56, 44, 98]
这里clone()的返回值是Object,所以需要ArrayList)进行类型转换为整数型的动态数组
参考来源 http://www.w3school.me/java/java-arraylist-clone.html
public boolean contains(Object o)
- 功能:如果此列表包含指定的元素,则返回true。
Integer i = 100;
System.out.println(data.contains(i));
//true
public void ensureCapacity(int minCapacity)
- 功能:增加此 ArrayList实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。虽然ArrayList会动态扩容,但是手动确定数组长度可以减少自动扩容花费的时间
ArrayList<String> names = new ArrayList<>();
names.ensureCapacity(3);
names.add("张三");
names.add("李四");
names.add("王五");
System.out.println("Names:"+names);
//Names:[张三, 李四, 王五]
public void forEach(Consumer<? super E> action)
- 功能:对Iterable每个元素执行给定操作,直到处理Iterable所有元素或操作引发异常。 如果指定了该顺序,则按迭代顺序执行操作。没有返回值,原数组内容不变
//将lamda表达式传递给forEach
names.forEach((e)->{
e = e + "是傻子";
System.out.println(e);
});
// 张三是傻子
// 李四是傻子
// 王五是傻子
public E get(int index)
- 功能:返回此列表中指定位置的元素
System.out.println(names.get(2));
//王五
public int indexOf(Object o)
- 功能:返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1。
System.out.println(names.indexOf("王五"));
//2
System.out.println(names.indexOf("赵六"));
//-1
- 类似的
public int lastIndexOf(Object o)
public boolean isEmpty()
- 功能:判断数组是否为空
ArrayList<String> names1 = new ArrayList<>();
System.out.println(names1.isEmpty());
//true
public Iterator<E> iterator()
- 返回迭代器
Iterator<String> iterator = names.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
public E set(int index, E element)
- 用指定的元素替换此列表中指定位置的元素。
//data = [100, 99, 98, 97, 96, 95]
data.set(2,250);
System.out.println(data);
//[100, 99, 250, 97, 96, 95]
public int size()
- 返回此列表中的有效元素数。
System.out.println(data.size());
public List<E> subList(int fromIndex, int toIndex)
- 返回指定的fromIndex (包含)和toIndex (独占)之间的此列表部分的视图。 (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。 返回的列表支持所有可选的列表操作
//data = [100, 99, 98, 97, 96, 95]
List<Integer> data1 = data.subList(2, data.size());
System.out.println(data1);
//[98, 97, 96, 95]
public Object[] toArray()
- 以适当的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。
//data = [100, 99, 98, 97, 96, 95]
Object[] it = data.toArray();
System.out.println(Arrays.toString(it));
//[100, 99, 98, 97, 96, 95]
public <T> T[] toArray(T[] a)
- 以适当的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素); 返回数组的运行时类型是指定数组的运行时类型。
Integer[] it = new Integer[(data.size())];
data.toArray(it);
System.out.println(Arrays.toString(it));
//[100, 99, 98, 97, 96, 95]
public void trimToSize()
- 将此ArrayList实例的容量调整为列表的当前大小。 应用程序可以使用此操作来最小化ArrayList实例的存储。