文章引用: http://blog.csdn.net/softwave/article/details/4166598
Collection
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些 Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,而是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection;有一个 Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。
如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); // 获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); // 得到下一个元素
}
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素, 还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
LinkedList类
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
LinkedList基本操作Demo:
/**
* Program : CollectionDemo
* Author : yajun.liu
* Create : 2014年7月31日 下午11:09:21
*
* Copyright 2014 By yajun.liu, All rights reserved.
*
* LinkedListDemo基本操作集合.
*/
package com.liuyj.app;
import java.util.LinkedList;
/**
* LinkedListDemo.
* @author yajun.liu
* @since
* @param
*/
public class LinkedListDemo {
/**
* main.
* @author yajun.liu
* @create 2014-7-31 上午11:58:28
* @since
* @param args 参数
* @return
*/
public static void main(String[] args) {
LinkedList<String> lls = new LinkedList<String>();
lls.add("1");
lls.add("2");
lls.add("3");
lls.add("4");
lls.add("5");
lls.getFirst(); //获取第一个元素
lls.getLast(); //获取最后一个元素
lls.get(3); //获取某个索引元素
lls.addFirst("0"); //添加到头部
lls.addLast("9"); //添加到尾部
//栈操作
lls.pop(); //移除并返回此列表的第一个元素
lls.push("6"); //将该元素插入此列表的开头。
lls.poll(); //获取并移除此列表的第一个元素
lls.pollFirst(); //获取并移除此列表的第一个元素
lls.pollLast(); //获取并移除此列表的最后一个元素
lls.peek(); //获取但不移除此列表的第一个元素
lls.peekFirst(); //获取但不移除此列表的第一个元素
lls.peekLast(); //获取但不移除此列表的最后一个元素
printArray(lls.toArray(new String[0]));
}
/**
* 打印数组.
* @author yajun.liu
* @create 2014-7-31 上午11:15:43
* @since
* @param array 数组对象
* @return
*/
private static void printArray(String[] array) {
int arrayLen = array.length;
for (int i = 0; i < arrayLen; i++) {
System.out.print(array[i]);
if (i != arrayLen - 1) {
System.out.print(",");
}
}
}
}</span>
LinkedList实现队列操作(先进先出),队列相当于一条通路,先从一端走进去的先从另一端出来:
/**
* Program : CollectionDemo
* Author : yajun.liu
* Create : 2014年7月31日 下午11:10:48
*
* Copyright 2014 By yajun.liu, All rights reserved.
*
* LinkedList实现队列操作(先进先出).
*/
package com.liuyj.app;
import java.util.LinkedList;
/**
* LinkedList实现队列操作(先进先出).
* @author yajun.liu
* @since
* @param
*/
public class LinkedListImplQueue {
public static void main(String[] args) {
LinkedListImplQueue lliq = new LinkedListImplQueue();
Queue queue = lliq.new Queue();
for (int i =0; i < 10; i++) {
queue.put(i); //压入顺序0123456789
}
while (!queue.isEmpty()) {
System.out.print(queue.get());//取出顺序0123456789
}
}
/**
* 模仿队列操作.
* @author yajun.liu
* @since
* @param
*/
class Queue {
private LinkedList<Object> ll = new LinkedList<Object>();
public void put(Object o) {
ll.addFirst(o); //添加第一个元素
}
public Object get() { //移除并返回最后一个元素
return ll.removeLast();
}
public boolean isEmpty() { //判空
return ll.isEmpty();
}
}
}</span>
LinkedList实现栈操作(先进后出),栈相当于一个箱子,只有一个开口,先进去的在最里面,也就是最后出来:
/**
* Program : CollectionDemo
* Author : yajun.liu
* Create : 2014年7月31日 下午11:11:33
*
* Copyright 2014 By yajun.liu, All rights reserved.
*
* LinkedList实现栈的操作(先进后出).
*/
package com.liuyj.app;
import java.util.LinkedList;
/**
* LinkedList实现栈的操作(先进后出).
* @author yajun.liu
* @since
* @param
*/
public class LinkedListImplStack {
public static void main(String[] args) {
LinkedListImplStack llis = new LinkedListImplStack();
Stack stack = llis.new Stack();
for (int i = 0; i < 10; i++) {
stack.push(i); //压栈
}
while (!stack.isEmpty()) {
//System.out.print(stack.top());
System.out.print(stack.pop()); //出栈
System.out.print(",");
}
}
/**
* 模仿栈的操作.
* @author yajun.liu
* @since
* @param
*/
class Stack {
private LinkedList<Object> ll = new LinkedList<Object>();
public void push(Object o) {
ll.addFirst(o); //添加第一个元素
}
public Object pop() {
return ll.removeFirst(); //删除并返回第一个元素
}
public Object top() {
return ll.getFirst();
}
public boolean isEmpty() {
return ll.isEmpty();
}
}
}</span>
LinkedList实现简单的多线程操作:
/**
* Program : CollectionDemo
* Author : yajun.liu
* Create : 2014年8月2日 上午8:46:30
*
* Copyright 2014 By yajun.liu, All rights reserved.
*
* 实现LinkedList多线程简单操作.
*/
package com.liuyj.app;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* LinkedList的简单多线程操作.
* @author yajun.liu
* @since
*/
public class LinkedListThread {
private static final int COUNT = 5;
private boolean bNull = true;
static List<String> list = Collections.synchronizedList(new LinkedList<String>());
static LinkedListThread llt = new LinkedListThread();
public static void main(String[] args) {
productor p = llt.new productor(list);
costomer c = llt.new costomer(list);
p.start();
c.start();
}
/**
* 生产者类.
* @author yajun.liu
* @since
*/
class productor extends Thread {
List<String> list;
public productor(List<String> lt) {
this.list = lt;
}
public void run() {
for (int i = 0; i < COUNT; i++) {
synchronized (llt) {
while (!bNull) {
try {
llt.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
bNull = false;
list.add("a" + i);
System.out.println("生产者生产:" + list.get(0));
llt.notifyAll();
}
}
}
}
/**
* 消费者类.
* @author yajun.liu
* @since
*/
class costomer extends Thread {
List<String> list;
public costomer(List<String> lt) {
this.list = lt;
}
public void run() {
while (true) {
synchronized (llt) {
while (bNull) {
try {
llt.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
bNull = true;
System.out.println("消费者消费:" + list.remove(0));
llt.notifyAll();
}
}
}
}
}
ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法 并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
ArrayList基本操作Demo:
/**
* Program : CollectionDemo
* Author : yajun.liu
* Create : 2014年7月31日 下午11:08:06
*
* Copyright 2014 By yajun.liu, All rights reserved.
*
* ArrayList使用Demo.
*/
package com.liuyj.app;
import java.util.ArrayList;
/**
* ArrayList使用Demo.
* @author yajun.liu
* @since
* @param
*/
public class ArrayListDemo {
/**
* main.
* @author yajun.liu
* @create 2014-7-31 上午11:59:03
* @since
* @param args 参数
* @return
*/
public static void main(String[] args) {
ArrayList<String> als = new ArrayList<String>();
als.add("a");
als.add("1");
als.add("2");
als.add("3");
als.add("4");
//修改,获取元素
als.set(2, "b");
als.get(3);
//als.clear();
//判空,移除
if (!als.isEmpty()) {
als.remove(1);
}
printArray(als.toArray());
}
/**
* 打印数组.
* @author yajun.liu
* @create 2014-7-31 上午11:15:43
* @since
* @param array 数组对象
* @return
*/
private static void printArray(Object[] array) {
int arrayLen = array.length;
for (int i = 0; i < arrayLen; i++) {
System.out.print(array[i]);
if (i != arrayLen - 1) {
System.out.print(",");
}
}
}
}
Vector类
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和 ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了 Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException,因此必须捕获该异常。
Vector基本操作Demo:
/**
* Program : CollectionDemo
* Author : yajun.liu
* Create : 2014年7月31日 下午11:10:08
*
* Copyright 2014 By yajun.liu, All rights reserved.
*
* VectorDemo.
*/
package com.liuyj.app;
import java.util.Vector;
/**
* VectorDemo.
* @author yajun.liu
* @since
* @param
*/
public class VectorDemo {
/**
* main.
* @author yajun.liu
* @create 2014-7-31 上午10:35:02
* @since
* @param args 参数
* @return
*/
public static void main(String[] args) {
Vector<String> vs = new Vector<String>(4, 4);
vs.add("a");
vs.add("b");
vs.add("c");
vs.add("d");
vs.add("e");
// vs.clear();
//添加修改元素
vs.addElement("f"); //添加元素,往后添加
vs.insertElementAt("g", 5); //导入元素,后移
vs.setElementAt("h", 6); //设置元素,替代
int idx = vs.lastIndexOf("d"); //查找最后出现元素的索引
// int idx1 = vs.lastIndexOf("f", 4); //在索引4之前进行搜索元素“f”,未找到元素返回-1
if (idx > 0) {
System.out.println("最后一次出现'd'的位置:" + idx);
} else { /** 未找到元素返回-1*/
System.out.println("找不到该元素!");
}
String str = vs.elementAt(3); //查找索引出的元素
System.out.println("索引为3处的组件值:" + str);
//移除元素操作
vs.remove(3);
vs.remove("a");
vs.removeElement("b");
vs.removeElementAt(3);
int size = vs.size();
System.out.println("vector_size = " + size);
for (int i = 0; i < size; i++) {
System.out.print(vs.get(i));
if (i != size - 1) {
System.out.print(",");
}
}
}
}
Stack 类
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。
Set接口
Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。
很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
请注意:必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。
区别与联系:
----ArrayList && LinkedList:(可查看http://blog.csdn.net/i_lovefish/article/details/8042900)
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
----Vector && ArrayList:
1.同步:
Vector是同步的。这个类中的一些方法保证了Vector中的对象是/*相对线程安全*/的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带 来的不必要的性能开销。
2.数据增长:
从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目 超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最 后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初 始化大小来避免不必要的资源开销。
3.使用模式:
在ArrayList和Vector中,从一个指定的位置(通过索引)查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的,这个时间我们用 O(1)表示。但是,如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长:O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除 元素的索引位置。为什么会这样呢?因为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。这一切意味着什么呢?
这意味着,你只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是其他操作,你最好选择其他 的集合操作类。比如,LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的?O(1),但它在索引一个元素的使用缺比较慢 -O(i),其中i是索引的位置.使用ArrayList也很容易,因为你可以简单的使用索引来代替创建iterator对象的操作。LinkList也 会为每个插入的元素创建对象,所有你要明白它也会带来额外的开销。
最后,在《Practical Java》一书中Peter Haggar建议使用一个简单的数组(Array)来代替Vector或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为使用数组 (Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。