Java 集合系列03 ArrayList集合

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
    }
}
原文地址:https://www.cnblogs.com/homle/p/14631045.html