【CSDN博客迁移】Java核心技术笔记——数据结构(1)

java设计了一套集合(也叫容器)类库,来支持最常用的数据结构,Java集合类库采用接口与实现分离的原则。下面主要梳理集合接口,集合类(包括集合抽象类和具体实现类)。

1 Java集合接口

Java的集合接口关系图如下:

Java集合类接口图.png

集合有两个基本接口Collection和Map
(1) Collection接口的源码如下:

public interface Collection<E> extends Iterable<E> {
    // Query Operations
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    //返回迭代器对象,用来访问集合中的元素
    Iterator<E> iterator();
    //返回集合的对象数组
    Object[] toArray();
    //添加元素
    boolean add(E e);
    //移除元素
    boolean remove(Object o);
    //判断传入集合是否被包含
    boolean containsAll(Collection<?> c);
    //与传入集合求交集
    boolean retainAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
}

(2)Map用来存放键值对,Map接口源码如下:

public interface Map<K,V> {
    // Query Operations
    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    //获取对应k的值,如果没有这个值,则返回null,K可以为null
    V get(Object key);
    // Modification Operations
    //插入k和v,此处可以插入k为null的键值对,但是v不能为null
    V put(K key, V value);
    V remove(Object key);

    // Bulk Operations

    void putAll(Map<? extends K, ? extends V> m);
  
    void clear();

    // Views
    /*--注意从下面三个返回的集中,可以删除元素,与此同时也删除了Map中的元素,但是不能添加元素---***/
    
    //返回Map中所有K的Set集
    Set<K> keySet();
    //返回Map中所有V的Collection集合
    Collection<V> values();
    //整个键值对作为一个Set集返回
    Set<Map.Entry<K, V>> entrySet();
   
        interface Entry<K,V> {
            K getKey();
            V getValue();
            V setValue(V value);
            boolean equals(Object o);
            int hashCode();
        }
    // Comparison and hashing

    boolean equals(Object o);
    int hashCode();
}

注意,在Java中访问集合中某个位置元素,要使用迭代器(Iterator)。
(3)Iterator接口的源码如下:

public interface Iterator<E> {
//返回将要访问的下一个对象,如果已经是集合的最后一个元素,将抛出NoSuchElementException错误
E next();
//由于上面方法抛出错误,因此在访问集合元素之前,先判断是否有下一个元素
boolean hasNext();
//移除元素之前,要先使用next方法定位到改元素;
void remove();
}

List是一个顺序排列集合接口,List在特定位置添加元素的方法有两种,一种是整数索引,一种是列表迭代器。
(4)List接口的源码如下:

public interface List<E> extends Collection<E> {
    // Query Operations
    //继承Collection方法,参考Collection源码分析
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    ........
    
    // Positional Access Operations
    //获取给定位置的元素
    E get(int index);
    //用新元素取代给定位置元素,返回原来的元素
    E set(int index, E element);
    //通过整数索引,在给定位置添加元素
    void add(int index, E element);
    //移除给定位置的元素
    E remove(int index);
    // Search Operations
    //返回与给定元素相等的元素在列表中第一次出现的位置,如果没有返回-1
    int indexOf(Object o);
    //返回与给定元素相等的元素在列表中最后一次出现的位置,如果没有放回-1
    int lastIndexOf(Object o);
    
    // List Iterators
    //返回一个列表迭代器
    ListIterator<E> listIterator();
    //返回一个列表迭代器,第一次调用next后,返回的给定索引的元素
    ListIterator<E> listIterator(int index);

    // View
    //返回List的某个范围内的子集合
    List<E> subList(int fromIndex, int toIndex);
}

由于Collection有的子集合(如Set)是无序的,所以Iterator接口中无add方法,但是对于List子集合需要使用迭代器添加指定位置的元素,因此ListIterator继承Iterator,提供了add方法。
(5)ListIterator接口源码如下:

public interface ListIterator<E> extends Iterator<E> {
    // Query Operations
    //继承Iterator方法,参考Iterator源码分析
    boolean hasNext();
    E next();
    //反向迭代列表时,判断是否有元素
    boolean hasPrevious();
    //返回前一个对象,如果已经是集合的第一个元素,将抛出NoSuchElementException错误
    E previous();
    //返回下一次调用next方法后,元素的索引
    int nextIndex();
     //返回下一次调用previous方法后,元素的索引
    int previousIndex();
    // Modification Operations
    void remove();
    void set(E e);
    void add(E e);
}

Set接口和Collection接口的方法一样,这里Java为什么要定义一个新的接口?是为了从概念上区分集合与集,方面扩展。
SortedSet和SortedMap接口,顾名思义给开发者暴露了排序的方法,并可以返回某个范围内的子集
(6)SortedSet的源码如下:

public interface SortedSet<E> extends Set<E> {
    //用于排序的方法,参考后续章节具体实现类
    Comparator<? super E> comparator();
    //下面三个方法,返回给定范围内的子SortedSet集
    SortedSet<E> subSet(E fromElement, E toElement);
    SortedSet<E> headSet(E toElement);
    SortedSet<E> tailSet(E fromElement);
    
    E first();
    E last();
}

(7)SortedMap的源码如下:

public interface SortedMap<K,V> extends Map<K,V> {
    //用于排序的方法,参考后续章节具体实现类
    Comparator<? super K> comparator();
    //下面三个方法,返回给定范围内的子SortedMap
    SortedMap<K,V> subMap(K fromKey, K toKey);
    SortedMap<K,V> headMap(K toKey);
    SortedMap<K,V> tailMap(K fromKey);

    //下面三个方法和Map接口中方法一样,参考Map接口源码
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();
}

Java SE6引入了NavigableSet和NavigableMap接口,用来在有序集和Map中查找遍历方法
(8)NavigableSet源码如下:

public interface NavigableSet<E> extends SortedSet<E> {

    E lower(E e);
    E floor(E e);
    .......

    //下面三个方法主要返回给定范围内的子NavigableSet,boolean 标志是否包括边界值
    NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                           E toElement,   boolean toInclusive);

    NavigableSet<E> headSet(E toElement, boolean inclusive);
    NavigableSet<E> tailSet(E fromElement, boolean inclusive);
    //下面三个方法和SortedSet接口中方法一样,参考SortedSet接口源码
    SortedSet<E> subSet(E fromElement, E toElement);
    SortedSet<E> headSet(E toElement);
    SortedSet<E> tailSet(E fromElement);
}

(9)NavigableMap源码如下:

public interface NavigableMap<K,V> extends SortedMap<K,V> {

    Map.Entry<K,V> lowerEntry(K key);
    K lowerKey(K key);
    Map.Entry<K,V> floorEntry(K key);
    K floorKey(K key)
    Map.Entry<K,V> ceilingEntry(K key);
    ........
    
    //下面三个方法,返回给定范围内的键的NavigableMap,boolean 表示是否包括边界
    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
                             K toKey,   boolean toInclusive);
    NavigableMap<K,V> headMap(K toKey, boolean inclusive);
    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);

    //下面三个方法,与SortedMap方法一样,参考SortedMap源码
    SortedMap<K,V> subMap(K fromKey, K toKey);
    SortedMap<K,V> headMap(K toKey);
    SortedMap<K,V> tailMap(K fromKey);
}

队列是在尾部添加一个元素,在头部删除一个元素。双端队列是在头部和尾部都可以删除元素
(10)Queue的源码如下:

public interface Queue<E> extends Collection<E> {

    //当执行add往队列中添加元素时,如果队列没有满,则往队列尾部添加元素并返回true,否则add方法抛出异常,offer方法返回false
    boolean add(E e);
    boolean offer(E e);
    
    //当执行remove移除队列中头部元素时,如果队列不空,则移除头部元素并返回true,否则remove方法抛出异常,poll方法返回false
    E remove();
    E poll();
    
    //当执行element查看队列中头部元素时,如果队列不空,则返回队列中的头部元素,否则element方法抛出异常,peek方法返回null
    E element();
    E peek();
}

(11)Deque(双端队列接口)源码如下:

public interface Deque<E> extends Queue<E> {
    //当给定的对象添加到双端队列的头部和尾部时,如果队列满了,则前两个方法抛出异常,后两个方法返回false
    void addFirst(E e);
    void addLast(E e);
    boolean offerFirst(E e);
    boolean offerLast(E e);

    //当删除双端队列头部和尾部元素时,如果队列为空,则前两个方法抛出异常,后两个方法返回null
    E removeFirst();
    E removeLast();
    E pollFirst();
    E pollLast();

    //当查询双端队列头部和尾部元素时,如果队列为空,则前两个方法抛出异常,后两个方法返回null
    E getFirst();
    E getLast();
    E peekFirst();
    E peekLast();

    boolean removeFirstOccurrence(Object o);
    boolean removeLastOccurrence(Object o);

    // *** Queue methods ***

    //参考Queue 中的add、offer方法说明
    boolean add(E e);
    boolean offer(E e);
    //参考Queue 中的remove、poll方法说明
    E remove();
    E poll();
    //参考Queue 中的element、peek方法说明
    E element();
    E peek();

    // *** Stack methods ***
    void push(E e);
    E pop();

    // *** Collection methods ***
    //参考Collection 中的方法说明
    boolean remove(Object o);
    boolean contains(Object o);
    public int size();
    Iterator<E> iterator();
    Iterator<E> descendingIterator();
}

RandomAccess接口用于监测List随机访问的效率,该接口没有方法,ArrayList继承了该接口。
(12)RandomAccess源码:

public interface RandomAccess {

}

2. Java集合类

前面的Java集合接口中有大量的方法,这些方法主要通过抽象类和具体类实现。其中抽象类主要实现接口中一部分通用的方法,具体类针对具体的类型实现具体的方法。
下面是Java集合类图:

java集合类图.png

2.1 Java集合抽象类

对于公用的方法可在集合抽象类实现,一些具体的方法可抽象化在继承的有具体特征的子类中实现。集合抽象类主要有AbstractCollection、AbstractMap
AbstractList、AbstractSet、AbstractQueue、AbstractSequentialList
这里以AbstractCollection源码为例分析一下:
AbstractCollection的源码如下:

public abstract class AbstractCollection<E> implements Collection<E> {

    protected AbstractCollection() {
    }

    // Query Operations
    //Collection接口中方法,可根据不同的集合,具体实现。
    //迭代器方法和集合大小方法抽象。
    public abstract Iterator<E> iterator();
    public abstract int size();
    
    //下面所有的方法都在抽象类中实现
    public boolean isEmpty() {
        return size() == 0;
    }
    
    //用迭代器,访问逐次访问集合中的元素,判断是否包含给定的对象
    public boolean contains(Object o) {
        Iterator<E> it = iterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return true;
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))
                    return true;
        }
        return false;
    }

    //逐次访问集合中的元素,转换集合中对象为数组
    public Object[] toArray() {
       //根据集合大小定义数组
        Object[] r = new Object[size()];
        Iterator<E> it = iterator();
        for (int i = 0; i < r.length; i++) {
            if (! it.hasNext()) 
               // fewer elements than expected
                return Arrays.copyOf(r, i);
            r[i] = it.next();
        }
        return it.hasNext() ? finishToArray(r, it) : r;
    }

    public <T> T[] toArray(T[] a) {
        // Estimate size of array; be prepared to see more or fewer elements
        int size = size();
        T[] r = a.length >= size ? a :
                  (T[])java.lang.reflect.Array
                  .newInstance(a.getClass().getComponentType(), size);
        Iterator<E> it = iterator();

        for (int i = 0; i < r.length; i++) {
            if (! it.hasNext()) { // fewer elements than expected
                if (a != r)
                    return Arrays.copyOf(r, i);
                r[i] = null; // null-terminate
                return r;
            }
            r[i] = (T)it.next();
        }
        return it.hasNext() ? finishToArray(r, it) : r;
    }

    //Integer.MAX_VALUE是int整形的最大取值2的31次方-1,这个常量用来控制集合的最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
        int i = r.length;
        while (it.hasNext()) {
            int cap = r.length;
            if (i == cap) {
                int newCap = cap + (cap >> 1) + 1;
                // overflow-conscious code
                if (newCap - MAX_ARRAY_SIZE > 0)
                    newCap = hugeCapacity(cap + 1);
                r = Arrays.copyOf(r, newCap);
            }
            r[i++] = (T)it.next();
        }
        // trim if overallocated
        return (i == r.length) ? r : Arrays.copyOf(r, i);
    }

    //返回集合的最大容量值
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError
                ("Required array size too large");
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    // 添加对象方法实现
    public boolean add(E e) {
        throw new UnsupportedOperationException();
    }
    //移除对象方法实现
    public boolean remove(Object o) {
        Iterator<E> it = iterator();
        if (o==null) {
            while (it.hasNext()) {
                if (it.next()==null) {
                    it.remove();
                    return true;
                }
            }
        } else {
            while (it.hasNext()) {
                if (o.equals(it.next())) {
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }

    //批量操作方法实现
    //判断传入集合是否被包含方法实现
    public boolean containsAll(Collection<?> c) {
        for (Object e : c)
            if (!contains(e))
                return false;
        return true;
    }
    //添加传入集合方法实现
    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }
    //移除传入集合方法实现
    public boolean removeAll(Collection<?> c) {
        boolean modified = false;
        Iterator<?> it = iterator();
        while (it.hasNext()) {
            if (c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
    }
    //实现与传入集合求交集方法
    public boolean retainAll(Collection<?> c) {
        boolean modified = false;
        Iterator<E> it = iterator();
        while (it.hasNext()) {
            if (!c.contains(it.next())) {
                it.remove();
                modified = true;
            }
        }
        return modified;
    }

    //对象转换为字符串
    public String toString() {
        Iterator<E> it = iterator();
        //如果集合中对象为null,返回"[]"
        if (! it.hasNext())
            return "[]";
        //拼接字符串
        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }
}

2.2 Java集合具体实现类

我们项目中经常使用的具体类(Java集合类图中具体类)主要有LinkedList、ArrayList、HashSet、TreeSet、PriorityQueue、Array、Deque、HashMap、TreeMap,这些类的源码解析,见后续章节的分析;
下面是Java集合具体类的主要特征,如下表:

具体集合类特征.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,623评论 18 399
  • Java源码研究之容器(1) 如何看源码 很多时候我们看源码, 看完了以后经常也没啥收获, 有些地方看得懂, 有些...
    骆驼骑士阅读 993评论 0 22
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,497评论 0 3
  • 深秋的江风吹拂在身上,让忙碌的心瞬间得到放松,江水翻滚着向前,发出拍打江岸的响声,弯弯的月亮悬挂在天空,记...
    风清扬聊红尘阅读 598评论 2 8
  • 【一】 只是在特定的时间爱上了一个人。 再也走不出来。 2006年11月,初识。 2007年1月,恋爱。 2007...
    魔女刘阅读 1,009评论 0 2