ArrayList
ArrayList的概述
ArrayList是Java中的一个类,实现了List接口,可以动态的增加或者减少元素的大小
ArrayList是一个数组实现的列表,它可以存储不同类型的元素,如整数、字符串、对象等。
ArrayList的容量会根据需要自动增加或减小,因此不需要手动指定大小。
ArrayList还提供了许多有用的方法,如add()、remove()、get()等,可以方便地操作列表中的元素。
- 底层采用线形结构中的数组结构,
- 查询数据快(基于数组索引(index)找到对应的元素)
- 删除,添加速度慢(数组结构,数据在内存中是连续存放的,不管是删除还是添加,之后的数据都会变动)
- 线程不安全的
- 可以添加重复数据
- 长度可修改,可以添加元素和删除元素
- 随着向ArrayList中不断添加数据,其容量也会自动增加(扩容机制)
创建方式
//向上转型
List list = new ArrayList();
//创建一个容量为10的空列表
ArrayList arrayList = new ArrayList();
//创建一个容量为5的空列表
ArrayList arrayList = new ArrayList(5);
源码分析:
- 默认的初始容量
private static final int DEFAULT_CAPACITY = 10;
- 默认的容量空元素数据
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
- 储存数据的数组
- transient : 该数组不参加序列化,反序列化
- 初始化时容量为0
- 数组中添加1-10个元素时,它的长度扩容到10,如果超出则扩容自生的1.5倍
transient Object[] elementData;
-
构造方法
-
实例化时,构建出一个容量为的列表
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
-
实例化时,构建一个指定容量的空列表
public ArrayList(int initialCapacity) { //容量大于0时 if (initialCapacity > 0) { //创建一个指定容量的列表 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //容量等于0时创建一个空列表 this.elementData = EMPTY_ELEMENTDATA; } else { //容量不合法(负数)时,报异常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
-
实例化时,构造一个包含指定colledtion的元素列表,
public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray(),可能不返回Object[] if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 替换为空的列表 this.elementData = EMPTY_ELEMENTDATA; } }
-
ArrayList集合API操作
给List集合添加元素
add():
//将指定的元素添加到此列表的尾部。
public boolean add(E e) {
ensureCapacityInternal(size + 1);
//将数据添加到数组中的最后一个元素中,同时size长度加一
elementData[size++] = e;
return true;
}
//将指定的元素插入此列表中的指定位置。
public void add(int index, E element) {
//校验索引是否合法
rangeCheckForAdd(index);
//长度加一
ensureCapacityInternal(size + 1);
//数据拷贝
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//将数据赋值到指定索引中
elementData[index] = element;
size++;
}
addAll():
//将一个(collection)容器中所有的元素,添加到此列表的尾端
boolean addAll(Collection<? extends E> c);
//将一个(collection)容器中所有的元素,添加到此列表中指定的位置
boolean addAll(int index, Collection<? extends E> c);
//添加元素
public static void test2(){
List list = new ArrayList();
list.add("admin");
list.add(10);
list.add('c');
list.add(true);
list.add(2, "guest");
List List1 = new ArrayList();
smallList.add(100);
smallList.add(1000);
//添加一个集合
list.addAll(List1);
list.addAll(4,List1);
System.out.println(list);
}
修改指定元素、获取元素(set 、 get)
set():
//修改指定位置的元素
public E set(int index, E element) {
//校验索引是超出数组长度
rangeCheck(index);
//将索引位置的值赋值
E oldValue = elementData(index);
//将索引位置的元素重新赋值
elementData[index] = element;
return oldValue;
}
get():
//获取指定元素的值
public E get(int index) {
//校验索引是超出数组长度
rangeCheck(index);
//返回当前索引的值
return elementData(index);
}
public static void test3(){
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);
//修改指定的元素
list.set(1, "X");
System.out.println(list);
//通过下标获取元素
Object obj = list.get(1);
System.out.println(obj);
}
List容器中的包含的值与搜索值
contains():
//查找是否包含某个元素
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
- containsAll ()
//检索集合中的数据是否包含另一个集合的元素
boolean containsAll(Collection<?> c);
- indexOf ()
//返回数据相应的索引
int indexOf(Object o);
- lastIndexOf()
//返回数据相应的索引从最后检索
int lastIndexOf(Object o);
//List容器中的包含与索引
public static void test4(){
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
//检查是否包含某个元素
boolean is = list.contains(12);
System.out.println(is);
List smallList = new ArrayList();
smallList.add('a');
smallList.add('b');
list.addAll(smallList);
//检查是否包含某个指定的集合
is = list.containsAll(smallList);
System.out.println(is);
System.out.println(list);
//搜索指定的元素,返回下标(没有则返回-1)
int index = list.indexOf('x');
System.out.println(index);
//反向搜索
index = list.lastIndexOf('a');
}
容器迭代器的使用
-
所谓的迭代器,就是获取容器中的元素的一种方式而已;
-
iterator ():
//返回按适当顺序在列表的元素上进行迭代的迭代器。
Iterator<E> iterator();
- listIterator():
//返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
ListIterator<E> listIterator();
// 使用迭代器来获取元素
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
//list容器有着自己专属的迭代器
ListIterator listIterator = list.listIterator();
//System.out.println(listIterator.hasNext());//判断是否存在数据
//System.out.println(listIterator.previous());//判断是否存在数据
//从迭代器中获取数据获取值
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
//当前指针指向最后数据“3”,从后往前遍历数据
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
集合容器提供一个专有的迭代器,针对集合数据进行提取
List集合同时还有自己专属的一个迭代器,处理起来比较灵活。
List容器中元素的移除(remove 、removeAll)
- remove ():
//根据索引删除元素
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//获取要删除的index
int numMoved = size - index - 1;
if (numMoved > 0)
//数据拷贝
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//长度递减,当前索引位置的元素赋null值
elementData[--size] = null;
return oldValue;
}
- removeAll():
//从列表中移除指定 collection(容器)的值 中包含的其所有元素(可选操作)。
boolean removeAll(Collection<?> c);
public class Demo3 {
private static List list = new ArrayList();
private static List smallList = new ArrayList();
static {
list.add("a");
list.add("b");
list.add("c");
list.add("d");
smallList.add(1);
smallList.add(2);
smallList.add(3);
list.addAll(smallList);
}
public static void main(String[] args) {
test1();
}
// 元素的移除
public static void test1() {
System.out.println(list);
// 通过下标移除元素-----得到的是移除的元素本身
/*
* Object obj = list.remove(1);
* System.out.println(list);
* System.out.println(obj);
*/
// 通过指定的元素进行移除
/*
* boolean is = list.remove("b"); System.out.println(is);
* System.out.println(list);
*/
/*boolean is = list.remove(new Integer("1")); //复合引用类型的Integer代表的是移除指定的元素,而不是下标,下标是一个int类型的值;
System.out.println(is);
System.out.println(list);*/
//移除指定的容器
boolean is = list.removeAll(smallList);
System.out.println(is);
System.out.println(list);
}
如何在List容器中删除自定义的对象元素
package com.it.www.beans;
public class Person extends Object{
private String name;
private Integer age;
public Person(){
}
public Person(String name,Integer age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (o instanceof Person){//参数对象比较Person类,对象运算符,一个类是否属于另一个类,包含子类
//将父类转换为子类(向下转型)
Person person = (Person) o;
if (this.name.equals(person.name) && this.age == person.age){
return true;
}
}
return false;
}
@Override
public String toString() {
return name+","+age;
}
}
public class MethodGeneric {
private static List list = new ArrayList();
private static List list1 = new ArrayList();
public static void main(String[] args) {
System.out.println(list);
}
//静太代码块的作用:随着类的加载进行加载
static{
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list1.add("a");
list1.add("b");
list1.add("c");
list1.add("d");
list.addAll(list1);//1234abcd
list.add(new Person("张三", 18));
list.add(new Person("李四",19));
}
}
以下这几个方法,大家自己学习一下:
- retainAll()
//保留指定集合的所有元素
boolean retainAll(Collection<?> c);
- subList()
//截取集合中的元素
List<E> subList(int fromIndex, int toIndex);
- toArray()
//将集合转为数组
Object[] toArray();
- isEmpty()
//检查集合是否为null,为null返回ture,相反为false
boolean isEmpty();
clear:
//清除所有数据
public void clear() {
//修改次数递增
modCount++;
//循环将所有元素赋null值
for (int i = 0; i < size; i++)
elementData[i] = null;
//长度赋0值
size = 0;
}
扩容机制
ArrayList的扩容机制是在添加元素时,判断当前元素个数是否已经达到了数组容量,如果达到了就会进行扩容操作
扩容操作会创建一个新的数组,将原数组中的元素复制到新数组中,同时将新元素添加到新数组中
扩容的大小通常是原数组容量的一半,即增加原来的50%
下面是 ArrayList 中的扩容方法 ensureCapacityInternal 的源码实现
//该方法保证ArrayList有足够的容量保证一定数量的元素
//当ArrayList中的数据数量超过当前的容量,就需要调整他的大小
private void ensureCapacityInternal(int minCapacity) {
//检查该数组是否为默认的空数组,
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果是该方法将最小的容量设置为默认容量或者指定最小容量,以最大容量为主
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//然后调用ensureExplicitCapacity使用最小容量
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
//记录ArrayList的修改次数
modCount++;
//检查最小容量是否大于elementData数组的当前容量
if (minCapacity - elementData.length > 0) {
//条件满足调用grow方法来增加ArrayList的容量
grow(minCapacity);
}
}
private void grow(int minCapacity) {
//当前的数组长度赋值给变量
int oldCapacity = elementData.length;
//将当前的容量加到当前容量的一半来计算ArrayList的新容量
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新的容量依旧小于最小容量,则使用最小容量,
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//如果新的容量超过最大数组容量,
if (newCapacity - MAX_ARRAY_SIZE > 0) {
//调用hugeCapacity(计算可能的最大容量)
newCapacity = hugeCapacity(minCapacity);
}
//最后将数组的新的长度复制给新的容器
elementData = Arrays.copyOf(elementData, newCapacity);
}