注意:容器的嵌套组合常用于构建较为复杂的对象。
ArrayList : 优于随机访问,劣于插入删除
Set :不存储相同元素,优于元素归属查询,多用于查询操作较为频繁的场合
HashSet:内部用散列实现,优于查询。
TreeSet:内部用红黑树实现。
Map :Map用于将对象映射到其他对象。解决对象之间的映射与追踪问题。
Stack:后进先出
Queue: 先进先出,一种可靠的将对象从程序的某个区域传输到另一个区域。多用于并发编程。
PriorityQueue: 优先级队列。
此处,针对Queue,需要进一步说明的是,队列规则是指在给定一组队列中元素的情况下,确定下一个弹出队列元素的规则。
先进先出声明的是下一个元素应该是等待时间最长的元素。
优先级队列声明的是下一个弹出元素是最需要的元素,即具有最高优先级的元素。
在java中,优先级可以用Comparator的各种子类实现来定义,在PriorityQueue的构造方法中传入。
面向过程编程
面向对象编程
面向接口编程:通过针对接口而非具体的对象进行编程,使得代码可以应用于更多的对象类型。
映射表(Map)
映射表的基本思想是它维护的是键-值(key-value)关联。标准的java类库中包含了Map的集中基本实现,包括:HashMap,TreeMap,LinkedHashMap,WeakHashMap,ConcurrentHashMap,IdentityHashMap。他们都具有相同的基本接口Map,但是行为特征不同,主要表现在效率、键值对的保存及呈现顺序、对象的保存周期、映射表如何在多线程程序中工作和判定“键”等价的策略等方面。
HashMap*:Map基于散列表的实现,插入和查询的开销是固定的,可以通过构造器设置容量因子和负载因子,以调整容器的性能。
LinkedHashMap:类似于HashMap,取得“键值对”的顺序是其插入顺序,其使用链表维护内部次序。
TreeMap:基于红黑树的实现,实现了SortedMap接口,查看键或键值对时,他们会被排序(次序由Comparator或Comparable决定)。TreeMap得到的结果是排过序的,且是唯一的带有subMap()方法的Map,可返回一个子树。
public interface Map<K,V> {
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> m);
void clear();
Set<K> keySet();
Collection<V> values();
//The <tt>Map.entrySet</tt> method returns
* a collection-view of the map, whose elements are of this class.
Set<Map.Entry<K, V>> entrySet();
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
}
boolean equals(Object o);
int hashCode();
}
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
}
注意:Collection接口内部并不包括随机访问所选择的元素的get(int index)方法,因为Collection包括Set,而Set是自己维护内部顺序的(这使得随机访问变得没有意义)。因此,如果想检查Collection中的元素,就必须使用迭代器。
Set 接口
Set<MyClass> set;
当在Set中创建自己的类型时,要意识到Set需要一种方法来维护存储顺序,而存储顺序的维护在不同的实现中也是不同的。不同的Set实现不仅具有不同的行为,同时也对Set中放置的元素类型也有不同的要求。
Set(Interface):存入Set的每个元素都必须使唯一的,因为Set不保存重复元素,加入Set的元素必须定义equals()方法以确认对象的唯一性。Set与Collection有完全一样的接口,Set接口不保证维护元素的顺序。
HashSet*:为快速查找而设计的Set。存入Set的元素必须定义hashCode()方法。
TreeSet :保持次序的Set,底层为树结构,使用它可以从Set中提取有序的序列。元素必须实现Comparable接口。
LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入顺序)。于是在使用迭代器遍历Set时,结果会按照插入时的次序显示。元素必须定义hashCode()方法。
对于良好的编程风格而言,在覆盖equals()方法的同时,总是覆盖hashCode()方法。
个人理解:hashCode()方法继承在Object基类,用于表明对象的唯一性。同时,在虚拟机实现层面,应该便于对象的查找。
总结:
容器之间的区别通常归结为由什么在背后“支持”他们,也就是说,所使用的接口是由什么样的数据结构实现的。