ArrayList和Vetor是List两个典型的实现类。
他们都是基于数组的实现类。内部都封装了一个动态的,允许再分配的Object[]数组。
他两方法基本都相同。除了,ArrayList是线程不安全的类,多个线程访问ArrayList,超过一个修改ArrayList,则必须手动保证ArrayList的同步性。虽然Vetor是线程安全的,但是也不推荐使用。而且用Collections工具类保证线程安全。
值的一提的是Vetor有个子类Stack。模拟了栈这种数据结构。后进先出。进出栈都是Object,取出元素后必须进行类型转换。
有方法:
Object peek()返回栈的第一个元素,不把该元素压出栈
Objject pop() 返回栈的第一个元素,并将该元素压出栈
Void push(Object o)将元素进栈,位于栈顶。
Stack线程安全但是安全性能差,需要用栈的数据结构,推荐使用ArrayDeque(后面提)
ArrayDeque也是List的实现类,也是Deque的实现类
下示例ArrayDeque作为栈使用的用法
package Test01;
import java.util.ArrayDeque;
public class TestDeque {
public static void main(String[] args) {
ArrayDeque a =new ArrayDeque();
ArrayDeque b =new ArrayDeque();
b.push("第一");
b.push("第二");
b.push("第三");
System.out.println(a.peek());
System.out.println(a.pop());
System.out.println("第二次a是"+a);
a.push("第四");
System.out.println(a); //仔细观察顺序
}
}
同时ArrayDeque也是Deque接口的子接口,也能作为双端队列使用,Deque接口定义了双端队列的方法,允许从两端操作队列。
方法(略看一下):
void addFirst(Object o)将指定元素插入双端队列的开头
void addLastObject o)将指定元素插入双端队列的结尾
Iterator descendingiterator返回该双端队列的迭代器,会用逆向顺序迭代该集合元素。
boolean offerFirst(Object o)将指定元素插入双端队列的开头
boolean offerFirst(Object o)将指定元素插入双端队列的结尾
Object getFirst(Object o)获得但不删除该双端队列的第一个元素,
Object getLast(Object o)获得但不删除该双端队列的最后一个元素,
Object peekFirst(Object o)获得但不删除该双端队列的第一个元素,如果是空,返回null
Object peekLast(Object o)获得但不删除该双端队列的最后一个元素,如果是空,返回null
Object pollFirst(Object o)获得且删除该双端队列的第一个元素,如果是空,返回null
Object polLast(Object o)获得且删除该双端队列的最后一个元素,如果是空,返回null
Object pop() (栈方法)等价于Object removeFirst() 移除该双端队列的第一个元素
void push(Object o) (栈方法)等价于void addfirst(Object o) push该双端队列表示的栈的第一个元素
Object removeFirstOccurence(Object o) 删除该双端队列出现的第一个元素
Object removeLastOccurence(Object o) 删除该双端队列出现的最后一个元素
ArrayDeque也是Deque接口的一个典型的实现类。
PriorityQueue是比较标准的队列实现类,
但是注意: 他不是按添加顺序先进先出,会重新排序。因此在peek或poll取出元素时,会取出最小的
package Test01; import java.util.PriorityQueue; public class TestPriorityQueue { public static void main(String[] args) { PriorityQueue p =new PriorityQueue(); p.offer(6); p.offer(-3); p.offer(20); p.offer(18); System.out.println(p); //该结果可能看出PriorityQueue没有很好的按从小到大排序,受到toString()返回值影响。 p.poll(); System.out.println(p); p.poll(); System.out.println(p); p.poll(); System.out.println(p); p.poll(); System.out.println(p); //从这可看出仍是从小到大移除元素 } }
PriorityQueue不允许插入null元素,还需要对队列进行排序。PriorityQueue队列对元素的要求和TreeSet基本一致,也有类似自然排序和定制排序两种。
不能随机访问队列。
固定长度的List
背景知识:有个操作数组的工具类Arrays,这个类有个方法aslist(Object....a)可以把数组和指定个数的对象转为List集合。
注意:这个List集合不是ArrayList实现类的实例,也不是Vetor实现类的实例。是Arrays的内部类ArrayList的实例
package Test01; import java.util.Arrays; import java.util.List; public class TestAslist { public static void main(String[] args) { List<String> fixedList =Arrays.asList("你好啊","天天天蓝"); /* fixedList.forEach(System.out::printIn()); */ fixedList.add("可以添加吗"); fixedList.remove("可以删除吗"); } }
运行结果
LinkedList实现类
是List接口的实现类,可以当做List集合,通过索引随机访问集合元素。还实现了Deque接口,可被作为栈也可被作为双端队列使用。
下例子示范了强大功能
package Test01; import java.util.LinkedList; public class TestLinkedList { public static void main(String[] args) { LinkedList p =new LinkedList(); p.offer("加入队列的尾巴"); p.push("加入栈顶"); p.offerFirst("加入队列的头部"); System.out.println("排序下"+p); for(int i=0;i<p.size();i++) { System.out.println(p.get(i)); } System.out.println(p.peekFirst()); System.out.println(p.peekLast()); p.poll(); //把栈顶元素压出栈 System.out.println(p); p.pollLast(); //把队列的最后一个元素删除 System.out.println(p); } }
注意:
LinkedList与ArrayList及ArrayDeque内部用Object[]数组维护不同,随机访问元素特强。。它是链表维护的,因此随机访问较差,但是插入,
删除性能比较好。虽然Vetor也是内部Object[]维护,但是为了实现线程同步
(实现的机制也不好),所以Vetor各方面都比较差。
对于内部是用数组Object[]维护的ArrayList及ArrayDeque,随机访问效果都比迭代的好。随机访问会被映射为对数组元素的访问。
总结下线性表的性能分析:
List集合是一个线性表接口,LinkedList(基于链的线性表)和ArrayList(基于数组的线性表)又是他的典型实现。Queue表示队列,Deque表示
双端队列(既能作为栈,又能作为队列)。
总体来说,ArrayList性能比LinkedList性能好,所以大多数时候想到ArrayList
对使用List集合的建议:
需要遍历List集合里的元素,对ArrayList和Vetor,用get()访问比较好,对LinkedList,Itertor迭代器访问更好。
如果需要经常插入,删除来改变包含大量数据的List集合的大小,考虑LinkedList,ArrayList和Vetor需要重新分配内部数组的大小,性能较差。
多个线程访问List里的集合,应该用上Collections工具类包装成线程安全的集合。