------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
ArrayList集合
-
创建ArrayList
ArrayList类集成了AbstractList类
ArrayList中有两个构造方法(方法名相同,方法参数不同叫做重载),默认构造方法通过调用ArrayList(int)来事项ArrayList的创建,传入的值为10
因为ArrayList类继承了AbstractList类,其中super调用了父类的默认构造方法,父类的该方法为一个空的方法(只有方法的声明,没有方法的实现),因此这段代码中最关键的是实例化了一个Object的数组,并将此数组付给了当前实例的elementData属性,Object的大小为传入的参数值,因此在调用空狗仔方法的时候,会创建一个大小为10的Object数组,因此可以看到ArrayList采用数组的方式来存放对象
-
-
插入对象:add(E)
-
- Add方法的实现
当调用add方法时候,首先基于ArrayList中已有的元素数量+1,产生一个名为minCapacity的变量,然后比较此值和Object数组的大小,如果此值大于Object数组值,那么先将当前的Object数组复制给一个数组对象,接着产生一个新的数组的容量值,此值的计算方法为当前数组值*1.5+1,如果得出的容量值仍然小于minCapacity,那么就以minCapacity作为新的容量值,在得出这个容量值后,调用ArrayList.copyOf来生成新的数组对象,如果想调整容量的增长策略,可集成ArrayList并覆盖ensureCapacity方法即可。
- ArrayList.copyOf方法的实现
首先创建一个新的数组对象,该数组对象的类型和之前ArrayList中元素类型一直,如果是Object类型,则直接通过new Object[newLenth]的方式来创建,如果不是Object类型,则通过Array.newInstance调用native方法创建相同类型的数组,在创建完新的数组对象后,调用System.arraycopy通过native方法将之前数组中的对象复制到新的数组中
- Add(int,E)方法的实现
将元素直接插入指定的int位置,这个方法的实现首相要确保插入的位置是目前数组中存在的,之后还要确保数组的容量够用,在完成这些动作之后,和add(E)的不同的地方就是他要将当前的数组对象进行一次复制,即将目前index以及其后的数据都往后挪动以为,然后才能将指定的index位置的赋值为传入对象,可见这中方式要多付出一次复制数组的代价。
- Set(int,E)
替换指定位置的对象,首先会检查传入的位置是否小于当前数组的长度,此方法的返回值为替换之前的当前位置的内容
- AddAll(Collection<? extends E> c)
实现方法和add方法相似
-
删除对象:remove(E)
当执行此方法时候,ArrayList首先判断对象是否为null,如果为null,则遍历数组中已经有值的元素,并比较是否为null,如果为null则调用fastRemove来删除相应位置的对象,fastRemove方法的实现方式为将index后的对象往前复制一位,并将数组中的最后一个设置为null,即释放了对此对象的引用,此方法返回true或false
如果传入元素不为null,唯一的不同在于通过E的equals来比较元素的值是否相同,如果相同则认为是需要删除对象的位置,则调用fastRemove方法来完成删除,此方法返回true或false
还提供了remove(index)方法来删除指定的对象,此方法比remove(e)多了一个数组范围的检测,但少了对象位置的查找,因此性能会更好,此方法返回删除的元素
- Remove方法
- fastRemove方法代码
- Remove(index)方法
-
获取单个对象:get(index)
-
传入参数为数组中元素的位置,然后进行数组长度的验证,然后返回数组中此位置的对象
- Get(index)方法
-
遍历对象:iterator()
-
Iterator方法有ArrayList的父类AbstractList实现,当每次调用iterate方法时,都会创建一个新的AbstractList内部类对象itr的实例,当调用此实例的hasNext方法时候,比较当前指向的数组的位置是否和数组中已有的元素大小相等,如相等则返回false,否则返回true
-
判断对象是否存在:contains(E)
方法的实现为遍历整个ArrayList中已经存在的元素,如果E为null,则直接判断已有元素是否为null,如为null,则返回true,如E不为null,则通过E.equals进行判断是否相等
IndexOf为从前往后查找
lastIndexOf为从后往前查找
- Contains(E)方法
- lastIndexOf方法
-
注意要点
-
- ArrayList是基于数组方式实现的,无容量的限制
- ArrayList在执行插入元素时可能要扩展,在删除元素时并不会减少数组的容量(如果希望缩小数组容量,可以调用ArrayList的trimToSize方法),在查找元素的时候,对非null的元素采用equals方式进行寻找
- ArrayList是非线程安全的
在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;
而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值
线程不安全测试代码
import java.util.ArrayList; import java.util.List; public class Demo implements Runnable { List<String> list1 = new ArrayList<String>(1);// not thread safe public void run() { try { Thread.sleep((int)(Math.random() * 2)); } catch (InterruptedException e) { e.printStackTrace(); } list1.add(Thread.currentThread().getName()); } public static void main(String[] args) throws InterruptedException { ThreadGroup group = new ThreadGroup("testgroup"); Demo t = new Demo(); for (int i = 0; i < 10000; i++) { Thread th = new Thread(group, t, String.valueOf(i)); th.start(); } while (group.activeCount() > 0) { Thread.sleep(10); } System.out.println(); System.out.println(t.list1.size()); // it should be 10000 if thread safe collection is used. } } |