概述
接口定义类型,抽象类实现骨架。抽象类不支持的实现方法便是细节。这种技巧在JCF中是标配。一来替客户端提供如何实现一个接口的最直接的参考。二来帮助客户端以此实现功能更强的接口。如Guava的集合也是参考这种模式。
抽象实现
抽象类的最重要分析是留下了哪些抽象方法,而留下的抽象方法是真正实现类的差异,而抽象类中的普通方法使用抽象方法来实现,而抽象方法实现由实现类实现,并且抽象类没有任何字段,所以也能从侧面体现留下的抽象方法的价值。可以认为抽象实现是模板模式的一种应用。
AbstractCollection
1 | //这是AbstractCollection最核心的两个抽象方法,其余方法实现均是调用这两者 |
isEmpty
1 | //非常简单,size()=0 |
contains
1 | //通过遍历迭代器来查找元素,元素为空,找出Collection中第一个为空的元素,元素不为空, |
add
1 | //抛出异常,因为子类可以实现可变或者不可变集合 |
remove
1 | //通过迭代器删除,equals方法很重要 |
containsAll
1 | //时间复杂度为O(n^2) |
addAll
1 | //modified来判断集合是否改变 |
removeAll
1 | //通过迭代器删除 |
clear
1 | //遍历迭代器,删除元素 |
我们可以看到抽象方法在实现普通方法时候是基本每个方法都会调用。
AbstractList
1 | //AbstractList抽象方法有两个,1是新定义的get 2是继承父类的size,而父类AbstractCollection中的抽象方法只实现了一个iterator(),因为对于List来说,iterator行为是确认的。但是get行为需要子类实现。 |
在AbstractList实现中,定义了Itr, ListItr两个迭代器,以及用于实现内部视图的SubList和RandomAccessSubList.
iterator
1 | public Iterator<E> iterator() { |
Itr
1 | private class Itr implements Iterator<E> { |
ListItr
ListItr实现了ListIterator接口,ListIterator和Iterator不同之处在于Iterator只支持向后遍历,但是ListIterator同时支持向后和向前遍历。也支持任意位置开始的遍历。
1 | public interface ListIterator<E> extends Iterator<E> { |
1 | private class ListItr extends Itr implements ListIterator<E> { |
SubList
RandomAccessSubList
AbstractSequentialList
AbstractSequentialList新加创建List迭代器的抽象方法listIterator。
1 | public abstract ListIterator<E> listIterator(int index); |
AbstractSet
AbstractSet没有新加任何抽象方法,由于继承了AbstractCollection,所以它的实现是基于iterator和size的。
AbstractMap
AbstractMap中的抽象方法只有entrySet,可以推断其他方法均是基于该方法实现的。因为键值对的唯一性,所以使用Set存储每一个Entry,虽然Entry好像是数据类,但是本质是有行为的类。每一个Entry代表了一个键值对,我们只能修改value,获取kv,但是不能修改key,这是Entry接口带来的契约,也是设计Entry的点,如果key可以被更新,那么这个map行为将变得不可预期。
1 | public abstract Set<Entry<K,V>> entrySet(); |
1 | //我们注意到Entry对KV的抽象, |
AbstractMap中提供了两个Map.Entry的实现,一个可变的SimpleEntry,一个不可变的SimpleImmutableEntry.SimpleEntry的实现非常简单,没有任何难以理解的地方,我们来看下:
SimpleEntry
1 | public static class SimpleEntry<K,V> implements Entry<K,V>, java.io.Serializable{ |
SimpleImmutableEntry
和SimpleEntry不同的地方在于setValue方法抛出UnsupportedOperationException异常。
1 | public V setValue(V value) { |
查询方法实现
1 | //查询操作 |
修改操作方法
1 | //put方法在这里没有实现,也没有办法实现,正如add方法在AbstractCollection/List/Set中无法实现一样 |
视图方法
1 | transient Set<K> keySet; |
1 | //key的视图是set,因为key不能重复,每个Map只有一个视图,每个视图通过entrySet引用了 |
1 | //因为value可以有重复的,所以使用Collection存储 |