选择接口的不同实现
1.Hashtable、Vector、Stack的特征是,它们是哦过去遗留下来的类,目的只是为了支持老的程序(最好不要在新的程序中使用它们)。
2.容器之间的区别在于,所使用的接口是由什么样的数据结构实现的。
一.对List的选择
1.对于背后有数组支撑的List和ArrayList,无论列表的大小如何,这些访问都很快速和一致;而对于LinkedList,访问的时间对于较大的列表将明显增加。
2.在使用迭代器插入心底元素时,对于ArrayList,当列表变大时,其开销变得很高昂,但是对于LinkedList,相对来说标低廉,并且不会随列表的尺寸的变化而变化。
3.在LinkedList中插入和移除的代价相当低廉,并且不随列表的尺寸反升变化,但是对于ArrayList,插入操作的代价特别高昂,并且其代价随着列表尺寸的增加而增加。
4.LinkedList对List对端点会进行特殊处理——这使得在将LinkedList用作Queue时,速度可以得到提高。
5.对于随机访问的get()和set()操作,背后由数组支撑的List只比ArrayList稍微快一点,但是对于LinkedList,相同的操作会变得异常引人注目的高昂。
6.CopyOnWriteArrayList是List的一个特殊的实现,专门用于并发编程。
二.对Set的选择
1.HashSet的性能基本上总是比TreeSet好,特别是在添加和查询元素时,而这两个操作也是醉重要的操作。
2.TreeSet存在的唯一原因时它可以维持元素的排序状态,所以,只有当需要一个排序好的Set时,才应该使用TreeSet。
3.由于内部支持排序,所以用TreeSet迭代通常比用HashSet要快。
4.对于插入操作,LinkedList比HashSet的代价更高,这是由维护链表所带来额外的开销造成的。
三.对Map的选择
1.除了IdentityHashMap,所有的Map实现的插入操作都会随着Map尺寸的变大而明显变慢。但是,查找的代价通常比插入要小得多。
2.TreeMap通常比HashMap要慢。TreeMap是一种创建有序列表的方式。树的行为是:总是保证有序,并且不必进行特殊的排序。
3.LinkedHashMap在插入时比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表。正是由于这个列表,使得其迭代速度更快。
4.HashMap使用的默认负载因子是0.75,这个因子在时间和空间代价之间达到老平衡。更高的负载因子可以降低表所需要的空间,但是会增加查找代价。
实用方法
一.List的排序和查询
1.List排序与查询的方法与对象数组所使用的相应方法有相同的名字与语法,只是用Collections的static方法代替Arrays的方法而已。
二.设定Collection与Map为不可修改
1.Collections中提供了static方法unmodifiableCollection()、unmodifiableList()、unmodifiableSet()、unmodifiableMap()、unmodifiableSortedSet()、unmodifiableMap()和unmodifiableSortedMap()能够将操作的容器设置为“只读”。转换完成后,人和会改变容器内容的操作都会引起UnsupportedOperationException异常。
2.使用“不可修改方法”将返回一个引用,使用这个引用替换掉原本的引用,这样就不用担心无意中修改了只读的内容。
三.Collection或Map的同步控制
1.Collections类有static方法synchronizedCollection()、synchronizedList()、synchronizedSet()、synchronizedMap()、synchronizedSortedSet()、synchronizedMap()和synchronizedSortedMap()能够同步整个容器,其语法与“不可修改方法”相似。
2.Java容器类类库采用快速报错机制。它会探查容器上的任何除了你的进程所进行的操作意外的所有变化,一旦它发现其他进程修改了容器,就会立刻抛出ConcurrentModificationException异常。当程序的不同部分修改同一个容器时,就有可能导致容器的状态不一致,所以,此异常提醒你,应该修改代码。
3.ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet都使用了可以避免ConcurrentModificationException的技术。
Java 1.0/1.1容器
一.Vector和Enumeration
1.在Java 1.0/1.1中,Vector是唯一可以自我扩展的序列,所以它被大量使用。基本上,可以将其看作ArrayList,但是具有又长又难记的方法名。
2.Java 1.0/1,1版的迭代器发明了一个新名字——枚举。Enumeration只有两个方法:boolean hasMoreElements(),如果此枚举包含更多的元素,该方法就返回true;另一个为Object nextElement(),该方法返回此枚举中的下一个元素(如果还有的话),否则抛出异常。
3.可以通过Vector()的方法elements()和Collections.enumeration(Collection<?> c)方法生成一个Enumeration。
二.Hashtable
1.现在的程序中已经没有理由再使用Hashtable了。
三.Stack
1.Stack是一个失败的设计,如果想要实现一个Stack,建议使用LinkedList自己实现:
public class Stack<T> {
private LinkedList<T> storage = new LinkedList<T>();
public void push(T v) { storage.addFirst(); }
public void peek() { return storage.getFirst(); }
public void pop() { return storage.removeFirst(); }
public boolean empty() { return storage.isEmpty(); }
public String toString() { return storage.toString(); }
}
2.BitSet
1.如果想要高效率地存储大量的“开/关”信息,BitSet是一个很好的选择。不过它的效率仅是对空间而言;如果想要高效的访问时间,BitSet比本地数组稍慢一点。
2.使用方法和Set一致,都是通过set()方法储存,get()方法取。
3.如果有一个可以命名的固定的标志集合,那么EnumSet与BitSet相比,通常是一个更好的选择。使用BitSet而不是EnumSet的理由只包括:只有在运行时才知道需要多少个标志;对标志命名不合理;需要对BitSet进行某些特殊操作。