1. ArrayList定义
ArrayList集合底层使用数组这种数据结构。ArrayList集合继承AbstractList集合,实现List,RandomAccess,Cloneable,java.io.Serializable接口。ArrayList集合是非线程安全的。
ArrayList的构造函数:
//默认构造函数,初始化容量为10 //Constructs an empty list with an initial capacity of ten ArrayList() //初始化指定容量的构造函数 ArrayList(int initialCapacity) //创建一个包含Collection的集合 ArrayList(Collection<? extends E> collection)
2. ArrayList集合的数据结构
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable transient Object[] elementData; private int size;
ArrayList集合包含两个重要的属性:elementData和size
(1)elementData是一个Object类型的数组,保存添加到ArrayList集合中的元素。elementData是一个动态数组,可以通过ArrayList(int initialCapacity)指定初始化容量;如果使用不带参数的构造函数则默认初始化容量是10;elementData数组的大小也会根据ArrayList容量的增长而动态增长,具体增长方式是ensureCapacity()方法。
(2)size属性是动态数组的大小;
3. ArrayList扩容
(1)使用无参数构造函数创建数组
public class Test{ public static void main(String[] args) { ArrayList list = new ArrayList(); for (int i = 0; i < 10; i++) { list.add(i); } list.add(11); } }
public boolean add(E e) { modCount++; add(e, elementData, size); return true; } private void add(E e, Object[] elementData, int s) { if (s == elementData.length) //开始时,s == elementData.length elementData = grow(); elementData[s] = e; size = s + 1; } private Object[] grow() { return grow(size + 1); } private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); //newCapacity()扩容 } private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //开始时,oldCapacity大小为0 int newCapacity = oldCapacity + (oldCapacity >> 1); //这时newCapacity也为0 if (newCapacity - minCapacity <= 0) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) return Math.max(DEFAULT_CAPACITY, minCapacity); //当添加第一个元素后,则设置数组大小为10 if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); }
说明:
第一种情况:使用无参数构造函数创建ArrayList时
(1)在add第一个元素时,那么ArrayList的长度就会初始化为10;当之后在添加时只会调用elementData[s] = e,给数组的下一个元素赋值,不会在调用grow()进行扩容;
(2)当数组的长度已经到10了,再次添加第11个元素时,则会再次进入grow()中进行扩容,新的容量大小是原来容量大小的1.5倍(newCapacity = oldCapacity + (oldCapacity >> 1)),即大小为15,并使用ArrayCopyof返回一个新的数组,新的数组中还未被使用的部分会默认使用null。
(2)使用有参数构造函数创建数组
public class Test{ public static void main(String[] args) { ArrayList list = new ArrayList(5); for (int i = 0; i < 5; i++) { list.add(i); } list.add(6); } }
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); } }
private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow(); elementData[s] = e; size = s + 1; }
说明:
第二种情况:使用有参数构造函数创建ArrayList时
(1)会初始化指定大小的一个ArrayList然后直接给里面add元素;
(2)当size == elementData.length时,会进入grow扩容,还无参数构造函数不一样的是不会进行初始化容量10的设置,会直接进行扩容原来容量的1.5倍后返回;
4. ArrayList的遍历方式
(1) 通过迭代器(iterator)遍历
Collection c = new ArrayList(); c.add("hello"); c.add("world"); c.add(100); c.add(new Person()); Iterator it = c.iterator(); while(it.hasNext()){ Object obj = it.next(); System.out.println(obj); }
//如果需要再次遍历,需要重置迭代器
/*Iterator it = c.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}*/
(2) 通过索引遍历
ArrayList c = new ArrayList(); c.add(1); c.add(2); c.add("hello"); c.add(new Person()); for(int i=0; i< c.size(); i++){ Object ob = c.get(i); System.out.println(ob); }
(3) 通过for循环遍历
ArrayList<Integer> al = new ArrayList(); al.add(100); al.add(200); al.add(300); for(Integer i : al){ //增强for底层还是调用的迭代器Iterator() System.out.println(i); }
5. ArrayList常用API方法
import java.util.ArrayList; import java.util.Collection; /* 集合中可以保存所有类型的元素,集合中保存的都是元素的内存地址,引用 集合中常用方法: 1. add() 集合中添加元素 2. size() 获取集合中元素的个数 3. clear() 清除集合中的元素 4. contains() 判断集合中是否包含指定的元素,返回布尔类型 5. remove() 移除集合中的元素,返回布尔类型 6. isEmpty() 判断集合是否为空,返回布尔类型 7. toArray() 集合转换为Object类型的数组 */ public class CollectionTest01 { public static void main(String[] args) { Collection c = new ArrayList(); //多态,向下转型 c.add(1); //自动装箱,实际保存的是内存地址 c.add(new Object()); c.add(3.14); c.add("hello"); c.add(new Person()); System.out.println("集合中元素的个数:"+c.size()); //5 c.clear(); System.out.println("集合中元素的个数:"+c.size()); //0 c.add("hello"); c.add("world"); c.add(1); c.add(new Object()); c.add(true); System.out.println("集合中元素的个数:"+c.size()); //5 boolean flag = c.contains("java"); //false System.out.println(flag); boolean flag1 = c.contains("hello"); //true System.out.println(flag1); boolean flag2 = c.remove(1); System.out.println(flag2); //true System.out.println("集合中元素的个数:"+c.size()); //4 boolean flag3 = c.isEmpty(); System.out.println(flag3); c.clear(); System.out.println(c.isEmpty()); c.add("hello"); c.add("world"); c.add(100); c.add(new Person()); Object[] obj = c.toArray(); for (int i = 0; i < obj.length; i++) { System.out.println(obj[i]); } } } class Person{}
6. 集合中contains方法和remove方法的使用
集合中contains()方法,判断集合中是否包含指定的元素。
contains()方法底层是equals()方法判断是否包含内容,不是比较的内存地址,equals()方法返回true则包含指定元素。
集合中remove()方法,删除集合中的指定元素。
remove()方法底层也是调用equals()方法,只要内容相同就可以删除指定元素。
import java.util.ArrayList; import java.util.Collection; public class CollectionTest04 { public static void main(String[] args) { Collection c = new ArrayList(); String s1 = new String("abd"); String s2 = new String("bdc"); c.add(s1); c.add(s2); System.out.println("元素的个数:"+c.size()); String x = new String("abd"); System.out.println(c.contains(x)); //true Collection cc = new ArrayList(); String s3 = new String("hello"); cc.add(s3); System.out.println("元素的个数:"+cc.size()); //1 String s4 = new String("hello"); cc.remove(s4); //remove底层也是调用equals System.out.println("元素的个数:"+cc.size()); //0 } }