Java集合框架之ArrayList

Java 集合可分为 Collection 和 Map 两大体系:

  • Collection接口:用于存储一个一个的数据,也称单列数据集合

    • List子接口:用来存储有序的、可以重复的数据(主要用来替换数组,"动态"数组)

      • 实现类:ArrayList(主要实现类)、LinkedList、Vector

    • Set子接口:用来存储无序的、不可重复的数据(类似于高中讲的"集合")

      • 实现类:HashSet(主要实现类)、LinkedHashSet、TreeSet

  • Map接口:用于存储具有映射关系“key-value对”的集合,即一对一对的数据,也称双列数据集合。(类似于高中的函数、映射。(x1,y1),(x2,y2) ---> y = f(x) )

    • HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties

ArrayList 介绍

ArrayList:

•始于JDK1.2

•作为List接口的主要实现类,一般情况下我们如果希望将一些内容存储下来会优先考虑采用ArrayList。

•使用数组作为数据存储的载体,其原理也是数组。

•针对于元素的获取/遍历效率高。

•针对于元素的频繁增删改效率低。

ArrayLIst底层的数据结构是数组,这个数组的初始容量是10 。在第一次执行 add方法的时候,首先会执行一个ensureCapacityInterval方 法,在这个方法中,会首先执行一个计算容量的方法,在这个方法中,首先会 进行一次判断,对存放元素的数组 和 默认的一个空数组 进行比较,如果他们 两个是一个地址,就证明这存放元素的这个数组此时是空的,那么就会返回默 认值10。  然后会进行判断,由于此时数组的容量仍是零,在进行下一步对返回的 minCapacity elementData 数组的长度进行比较的时候,由于 minCapacity > elementData.length ,会执行 if 语句内部的代码,执行grow 方法,在 grow方法中,会重新创建一个数组对象,这个数组对象就是初始容 量 10 ,然后把这个数组对象赋值给 elementData ,此时 element对象的容量 就变成了 10

jdk1.6 版本中, Array Iist 类在初始化的时候,容量会自动赋值为 10.前面我 介绍的是 jdk8 ,这二者有所不同。如果按照 1.6的做法,那么每当实现一个 ArrayList对象的时候就要给十个容量,如果后面没有用到的话那么就会造成 资源上的浪费,而 1.8的做法只是在用的时候再初始化容量,可以一定程度上 避免资源浪费。

常用方法

add方法:

add 方法,add方法的主要流程就是第一步先对容量进行一个判断,如果容量够的情况下,就可以直接添加;如果容量不够,那么就需要扩容,进入到 grow方法中,在这个方法里,首先会计算出一个基于原来容量 1.5倍大的容量,然后在对这个新计算出来的容量进行比较,看看它是否满足所需容量的大小,如果满足最终容量,就会取用这个值,如果不能满足,那么就取能够满足需求的最小容量的值。在确定容量大小之后,再对这个值进行一次合法性校验,然后通过 java.util.Arrays 类中的CopyOf方法,将原数组中的元素拷贝到一个容量为扩容之后大小的新数组中,然后再进行添加操作就可以按序添加了。这就是 add 方法的流程。如图:

首先执行calculateCapacity方法

得到容量之后判断容量够不够  

 

不够则执行grow方法 

 

对于 ArrayLIst 来说,如果经常进行扩容是一种很浪费资源的行为,所以如果在允许
的情况下,可以提前定义好容量,减少扩容的这个过程,进而增强效率。
get(int index):获取指定index处的元素
public E get(int index) {
        rangeCheck(index);<------首先,通过这行代码判断索引是否有效。

        return elementData(index); <-------------------通过这行代码拿到指定索引的元素
    }
E elementData(int index) {
        return (E) elementData[index];
}

remove方法:

//通过index,得到需要移动元素数目,从移除索引的元素的后面的所有的元素用arraycopy方法,往前提一位,覆盖掉你想移除的那个	。
public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
//这个原理和上面的差不多,就是加一个for循环。
public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);//除了没有返回值,和上面的remove方法基本相同。
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

indexof:这个方法很简单,就是从前往后遍历数组,调用equals方法(调用哪个equals决定你传入的形参 o 是什么类型的),遇到第一个与之相等的值    就返回index。

public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

lastIndexOf:

public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
//原理和indexOf一样,不过就是从后往前遍历数组罢了。
subList 方法:
subList ()方法执行的操作是对于ArrayList 进行部分截取,方法有两个参数 x,y ,截取的部分是 [x , y) 。方法的返回值是 一个 SubList 对象,这是一个 ArrayList 的内部类,继承自 AbstractList 接口。 在接返回值得时候时候一般是 List 类型。在进行 subList操作的时候要注意,操 作之后不能对原 arrayLIst进行修改,否则会抛出 concurrentModifyException 。因为 subList在截取的时候,并没有把原 arrayList 中的元素拿出来,而是和 arrayList共享一份数据。可以理解为这是两 个容器, subLIst 是一个小容器, arrayList是一个大容器,部分数据在小容器里,小容器在大容器里。所以 subList在对它里面的元素进行修改的时候,这时候我们读 arrayList里的元素发现,这里面被截取的那部分的元素也会随之改变。

 

可以看出元素的的地址是相同的,而这两个容器并不是一个地址,印证了之前的说
法。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值