A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© ithemazl 中级黑马   /  2015-8-26 10:58  /  564 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

ArrayList集合


1.创建ArrayList


ArrayList类集成了AbstractList类

ArrayList中有两个构造方法(方法名相同,方法参数不同叫做重载),默认构造方法通过调用ArrayList(int)来事项ArrayList的创建,传入的值为10



1.






因为ArrayList类继承了AbstractList类,其中super调用了父类的默认构造方法,父类的该方法为一个空的方法(只有方法的声明,没有方法的实现),因此这段代码中最关键的是实例化了一个Object的数组,并将此数组付给了当前实例的elementData属性,Object的大小为传入的参数值,因此在调用空狗仔方法的时候,会创建一个大小为10的Object数组,因此可以看到ArrayList采用数组的方式来存放对象



1.


1.插入对象: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)


替换指定位置的对象,首先会检查传入的位置是否小于当前数组的长度,此方法的返回值为替换之前的当前位置的内容



1.




1.


•AddAll(Collection<? extends E> c)

实现方法和add方法相似



1.删除对象:remove(E)


当执行此方法时候,ArrayList首先判断对象是否为null,如果为null,则遍历数组中已经有值的元素,并比较是否为null,如果为null则调用fastRemove来删除相应位置的对象,fastRemove方法的实现方式为将index后的对象往前复制一位,并将数组中的最后一个设置为null,即释放了对此对象的引用,此方法返回true或false

如果传入元素不为null,唯一的不同在于通过E的equals来比较元素的值是否相同,如果相同则认为是需要删除对象的位置,则调用fastRemove方法来完成删除,此方法返回true或false

还提供了remove(index)方法来删除指定的对象,此方法比remove(e)多了一个数组范围的检测,但少了对象位置的查找,因此性能会更好,此方法返回删除的元素



1.Remove方法


2.fastRemove方法代码




1.Remove(index)方法


1.获取单个对象:get(index)



传入参数为数组中元素的位置,然后进行数组长度的验证,然后返回数组中此位置的对象



1.Get(index)方法


1.遍历对象:iterator()



Iterator方法有ArrayList的父类AbstractList实现,当每次调用iterate方法时,都会创建一个新的AbstractList内部类对象itr的实例,当调用此实例的hasNext方法时候,比较当前指向的数组的位置是否和数组中已有的元素大小相等,如相等则返回false,否则返回true


1.判断对象是否存在:contains(E)


方法的实现为遍历整个ArrayList中已经存在的元素,如果E为null,则直接判断已有元素是否为null,如为null,则返回true,如E不为null,则通过E.equals进行判断是否相等

IndexOf为从前往后查找

lastIndexOf为从后往前查找



1.Contains(E)方法




1.lastIndexOf方法


1.注意要点



•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.

    }

}

1 个回复

倒序浏览
谢谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马