Java常用类库之ArrayList

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实例的存储。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值