(1).ArrayList
底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快,允许null的元素。它的实现不是synchronized的,如果多个线程访问一个ArrayList实例,并且至少有一个会对它进行修改的话,就必须对它使用外部synchronized
(2).LinkedList
底层的数据结构是链表,线程不同步,增删元素的速度非常快,查询慢。不允许出现null,否则会报NoSuchElementException异常。
(3).Vector
底层的数据结构就是数组,线程同步的,Vector无论查询和增删都慢,在不考虑线程同步时,被ArrayList替代。
ListIterator合适于双向遍历List集合,该迭代器包含较多操作集合的方法。
//去除重复元素 import java.util.*; class Person { private String name; private int age; Person(String name, int age) { this.name = name; this.age = age; } public int getAge() { return this.age; } public String getName() { return this.name; } public boolean equals(Object obj) { if (!(obj instanceof Person)) return false; Person p = (Person)obj; return this.name.equals(p.getName()) && this.age==p.getAge(); } } class Demo { public static void main(String[] args) { ArrayList al = new ArrayList(); al.add(new Person("java01", 11)); al.add(new Person("java02", 22)); al.add(new Person("java03", 33)); al.add(new Person("java03", 33)); al.add(new Person("java04", 44)); al = noRepeat(al); Iterator it = al.iterator(); while(it.hasNext()) { Person p = (Person)it.next(); sop("Name:" + p.getName() +" Age:"+ p.getAge()); } } public static void sop(Object obj) { System.out.println(obj); } public static ArrayList noRepeat(ArrayList a1) { ArrayList a = new ArrayList(); Iterator it = a1.iterator(); while(it.hasNext()) { Object p = it.next(); if(!a.contains(p)) //判断ArrayList是否存在一个元素contains(),必须做的一个动作即使用元素的equals()方法 a.add(p); //ArrayList的contains动作隐含了元素的equals } return a; } }
/* Vector 枚举应用 Strawberry2013-5-4 */ import java.util.*; class PrintStreamDemo { public static void main(String[] args) { Vector<String> v = new Vector<String>(); v.add("aaaaaa"); v.add("BBBBBBB"); v.add("aaa"); Enumeration e = v.elements(); while(e.hasMoreElements()) { System.out.println(e.nextElement()); } } }
对ArrayList的操作我们可以通过索引象来访问,也可以通过Iterator来访问,只要不对ArrayList结构上进行修改都不会造成ConcurrentModificationException,单独用索引对ArrayList进行修改也不会造成该问题,造成该问题主要是在索引和Iterator混用。可以通过JDK的源码来说明该问题。
/** *在Iterator的内部有个expectedModCount 变量, *该变量每次初始化*Iterator的时候等于ArrayList的modCount,modCount记录了对ArrayList的结构修改次数, *在通过Iterator对ArrayList进行结构的修改的时候都会将expectedModCount 与modCount同步, *但是如果在通过Iterator访问的时候同时又通过索引的方式去修改ArrayList的结构的话, *由于通过索引的方式只会修改modCount不会同步修改expectedModCount 就会导致 *modCount和expectedModCount 不相等就会抛ConcurrentModificationException, *这也就是Iterator的fail-fast,快速失效的。所以只要采取一种方式操作ArrayList就不会出问题, *当然ArrayList不是线程安全的,此处不讨论对线程问题。 * */ int expectedModCount = modCount; public E next() { checkForComodification();//判断modeCount与expectedModCount 是否相等,如果不相等就抛异常 try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove() { if (lastRet == -1) throw new IllegalStateException(); checkForComodification();//同样去判断modeCount与expectedModCount 是否相等 try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount;//此处修改ArrayList的结构,所以要将expectedModCount 于modCount同步,主要是AbstractList.this.remove(lastRet);的remove方法中将modCount++了,导致了modCount与expectedModCount 不相等了。 } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } //判断modCount 与expectedModCount是否相等,如果不相等就抛ConcurrentModificationException异常 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }