集合框架专题1-集合框架概述

来源:互联网 发布:网络百家家乐是真的吗 编辑:程序博客网 时间:2024/05/17 22:33

  集合框架概述

前言: 本文所采用的jdk版本为:jdk1.8.0_111。

        集合框架可以说是整个java的世界中对于数据操作方面,应该是最基础最重要的一套api了。从学生时代再到工作中一直都在频繁地使用着这套api,中间也断断续续地研究过部分源码,但是因为工作原因,一直没有能梳理一下这方面的知识,近期决定将集合框架中常用的一些类从源码级别入手,仔仔细细地梳理一下。
一、集合框架简述
集合框架支持两种类型的容器:
一种是为了存储一个元素集合,简称为集合(Collection)。
另一种是为了存储键/值对,称为图(Map)。
二、Collection
如果看过Collection整个接口和类的层次机构,会发现所涉及到的内容超级多,这里只列出我们最常用的一些类。
上图是Collection中常用的一些类的结构图,图中列出了一些我们实际应用中最常用的几个类的层级结构。
2.1. Collection接口
Collection接口是处理对象集合的根接口,公共方法如图(截取自eclipse):
从图中我们可以看出平时常用的像add、remove方法皆是在根接口中定义的,所以要弄懂集合框架,首先先弄清楚上面的这些方法分别代表什么意义,具体翻译可见官方文档,这里就不一一阐述了。
2.2 AbstractCollection
AbstractCollection中除了size和iterator以外,实现了Collection中所有的方法(注:但实际上add方法的实现也是放在子类中的),我们主要来看一下其中最常用的几个方法。
2.2.1. remove(Object o)
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;    }
remove方法,源码中可以看出该方法是采用迭代的方式,去寻找equals为true的值,并且remove之后直接返回,所以假如有多个相同的值,此方法也只能移除掉第一个找到的值,此时允许Object为null。

2.2.2. removeAll(Collection<?> c)
    public boolean removeAll(Collection<?> c) {        Objects.requireNonNull(c);        boolean modified = false;        Iterator<?> it = iterator();        while (it.hasNext()) {            if (c.contains(it.next())) {                it.remove();                modified = true;            }        }        return modified;    }
removeAll方法,该方法采用的仍旧是迭代,判断的方法是contains方法,该方法也是在AbstractCollection中用迭代的方式实现的,所以这个方法的执行一共是双重迭代。

2.2.3 addAll(Collection<? extends E> c)
    public boolean addAll(Collection<? extends E> c) {        boolean modified = false;        for (E e : c)            if (add(e))                modified = true;        return modified;    }
该方法是将参数c进行迭代,循环去调用add方法来进行添加元素操作。

2.2.4 add(E e) 
    public boolean add(E e) {        throw new UnsupportedOperationException();    }
AbstractCollection中不支持直接添加元素,否则会报错,这里可以看出AbstractCollection不进行对外服务,也就是本身不存储元素,只是将子类公用的一些方法进行实现。具体实际的应用场景皆是通过子类去实现的。

2.2.5 clear()
    public void clear() {        Iterator<E> it = iterator();        while (it.hasNext()) {            it.next();            it.remove();        }    }
该方法是采用迭代的形式,将集合内所有的元素全部删掉。

2.2.6 contains(Object)
public boolean contains(Object o) {        Iterator<E> it = iterator(); //定义迭代器        if (o==null) { //首先判断参数是否为null,如果为null,则迭代判断null元素,这里之所以单独判断Null,是为了屏蔽掉null元素引发的nullPointerException异常            while (it.hasNext())                if (it.next()==null)                    return true;        } else {            while (it.hasNext())//迭代循环判断元素是否相等                if (o.equals(it.next()))                    return true;        }        return false;    }
源码中可以看出该方法主要是判断集合内是否包含参数中的Object元素,判断是依据是equals方法,所以如果自定义的元素,可以重写equals方法来达到自己要的效果。

2.2.7 containsAll(Collection<?> c)
    public boolean containsAll(Collection<?> c) {        for (Object e : c)            if (!contains(e))                return false;        return true;    }
这里是对参数进行迭代,循环判断集合中是否包含参数c中的每一个元素,假如有一个不包含,则结果为false。

2.2.8 retainAll(Collection<?> c)
    public boolean retainAll(Collection<?> c) {        Objects.requireNonNull(c);        boolean modified = false;        Iterator<E> it = iterator();        while (it.hasNext()) {            if (!c.contains(it.next())) {                it.remove();                modified = true;            }        }        return modified;    }
这里是迭代集合中元素,然后判断该元素是否被参数c中包含,假如不包含,则删掉,包含则留下。整体解读下来,实际上就是取交集的意思。


最后,再特别说明一点,AbstractCollection 方法自身不对外服务,而是通过子类去构建实际应用的场景。
2.2.4中add(E e) 方法,实际上是没有实现具体方法,但是没有去写成抽象方法,而是默认抛出一个异常,这里也许很多人有疑问,既然没有具体实现该方法,为什么不干脆写成抽象方法呢?是因为在很多场景下,实际上这个方法用不到,但是如果写成抽象方法,则其非抽象子类必须要继承该方法,那么将会给人的感觉很奇怪。实际上在一些不可变集合中,去修改其内容,那么标准解决方案就是抛出一个UnsupportedOperationException异常,这里正是遵从了这个标准方案。
所以这种设计原则,一方面既能够保证子类可以重写该方法,另一方面又照顾了不适用该方法的场景,不去暴露不需要的方法给继承者,这在接口中有一个类似的原则:接口隔离原则。