system.objectdisposedexception: 已释放该集合_java 集合框架

java集合框架封装了很多我们常用的数据结构,如线性表List,数学概念上的集合Set,队列Queue,键值对映射Map,它们都是接口,根据相应接口下面还有许多实现的具体类.

一.Collection

代表了集合最高的抽象,把数据所依托的结构看成一个容器,每个数据是这个容器的元素.规定了基本的方法.

没有实现任何同步,要实现同步需自己重写

@param 集合中的元素

public interface Collection extends Iterable {

   Iterable接口:实现了此接口则可以调用iterator()方法

    1,查询操作

    查询集合中的元素个数,

    若大于Integer最大值则返回Integer最大值

    @return 集合中的元素个数

    int size();

    @return 若集合中不含任何元素返回true

    boolean isEmpty();

    如果集合中含有待验证的元素则返回true

    @param o 待验证的元素

    @return 如果含有则返回true

    @throws ClassCastException

    如果待判断元素与集合中元素不可比较

     @throws NullPointerException 

     如果待判断元素为空,

   而集合不允许含有空元素

    boolean contains(Object o);

    返回这个集合的一个迭代器。

    不保证元素按某种顺序返回

    除非这个集合是某个类的实例,它提供了这种保证

     @return 迭代器

    Iterator iterator();

    /**

     * 按插入元素的顺序返回一个数组

     *返回的数组是重新创建的,没有被引用

     * 这个方法充当了基于数组和集合之间的桥梁的作用

     * @return 包含该集合中的所有元素的数组

     */

     Object[] toArray();

    /**

    返回包含该集合中所有元素的数组;

    返回的数组的类型是指定的数组类型。

    如果集合适合于指定的数组,则返回含有集合元素的数组。

    否则,将使用指定类型创建一个新的数组

    指定的数组和这个集合的大小相等。

    如果这个集合在指定的数组中有空闲空间

    (即。这个数组比这个集合有更多的元素),

    元素在集合结束后的数组中,将被设置为null 

    若规定了集合中元素的顺序,则这个数组中元素的顺序

    应该和Iterator相同 

     * @param 包含集合的数组的类型

     * @return 包含该集合中的所有元素的数组

     * @throws ArrayStoreException

      如果指定类型不是集合中元素的超类

     @throws NullPointerException 如果指定的数组为空

    T[] toArray(T[] a);

    2,定义集合的操作

    确保集合中包含要加入的元素,

    若集合在调用此方法后改变返回true

    若集合不允许元素重复但要加入的元素已存在返回false

    若集合只是拒绝添加此元素,而不管集合中是否存在则应该抛出异常

    进行处理

     * @param e 要加入到集合中的元素

     * @throws UnsupportedOperationException 如果添加该元素不被

     集合支持

     * @throws ClassCastException 要添加的元素的类不被集合支持

     * @throws NullPointerException 要添加空元素,但集合不允许含有空元素

     * @throws IllegalArgumentException 如果元素的某些特点禁止它加入到当前集合中

     * @throws IllegalStateException 

     调用此方法时集合插入元素受限

     */

    boolean add(E e);

    如果集合存在移除元素

    若集合含有该元素并且删除成功返回true

     * @param o 要移除的元素

     * @throws ClassCastException 

     待删除元素与集合中元素不可比较

     * @throws NullPointerException 

     待删除元素为空但集合不允许为空

     * @throws UnsupportedOperationException 

     集合不支持删除操作

     */

    boolean remove(Object o);

    3,集合与集合之间的操作

    如果当前集合包含指定集合中所有元素返回true

    参见contains()方法

     * @param  c 待检查的集合

     * @throws ClassCastException 集合元素不可比较

     * @throws NullPointerException 

     */

    boolean containsAll(Collection> c);

    将另一个集合中所有元素加入到当前集合,相当于并集

    对于这个操作的同时若被加入的集合被修改了,

    操作是不确定的(同样适用于把集合自身加入到集合)

    参见add(Object)

     * @param c 待加入到当前集合的集合

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

     * @throws IllegalStateException 

     */

    boolean addAll(Collection extends E> c);

    删除此集合中包括的另一个集合的所有元素,相当于差集

     * @param c 要删除的集合

     * @throws UnsupportedOperationException

     * @throws ClassCastException

     * @throws NullPointerException 同前几个的情况,但是若参数中

     的集合也为空也抛出异常

     参见 remove(Object)

     参见 contains(Object)

     */

    boolean removeAll(Collection> c);

     只保留另一个集合中的元素,相当于交集

     * @param c 另一个集合

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     参见 remove(Object)

     参见 contains(Object)

     */

    boolean retainAll(Collection> c);

    清空集合

    void clear();

    4,比较和哈希

    应该按值进行比较而不是按照引用

    equals()应满足对称性

     * @param o 待比较的对象

     * @return 相等返回true

     *参见 Object#equals(Object)

     * 参见 Set#equals(Object)

     * 参见 List#equals(Object)

     */

    boolean equals(Object o);

    返回哈希码,若equals()为true则应有相同的哈希码

     * @return 集合的哈希码

     * @see Object#hashCode()

     * @see Object#equals(Object)

     */

    int hashCode();

二.AbstractCollection

1fcfc657a5f1f85932c61cd98693262a.png

AbstractCollection实现了Collection接口规定的大部分方法,减轻子类实现接口的负担,因为只要继承此抽象类即可.

很多方法的声明前文已说过,这里只看方法内容,不再说方法的用途. 

若想实现一个不用再添加元素的集合,

只需继承此类,并实现iterator()和

size()方法即可.

(原文是:To implement an unmodifiable collection,

 the programmer needs only to extend this class 

 and provide implementations for the iterator and size

 methods.unmodifiable词典的意思是adj.无法改变的,我感觉应该

 是初始化后不能再用add()方法再添加元素,跟下面的对应)

若想实现一个可以添加元素的集合,

应该覆盖这个类中的add()方法,

或者你可以抛出一个UnsupportedOperationException

异常,提示添加操作不被支持.另外

这个集合的迭代器应该实现remove()方法

(原文是: To implement a modifiable

 collection, the programmer must 

 additionally override this class's 

 add method ,which otherwise throws an

 UnsupportedOperationException ,and the

  iterator returned by the

  iterator method must additionally 

  implement its remove method.

)

每个继承这个类的子类应该含有一个

不含参数的构造函数

如果你想更高效的实现此类中的方法请自己覆盖重写

public abstract class AbstractCollection implements Collection {

    仅有的构造函数,为了子类在某种情况下调用

    protected AbstractCollection() {

    }

    1, 查询操作

    这是开头所说的没有实现的方法,返回集合的迭代器和集合的大小

    public abstract Iterator iterator();

    public abstract int size();
    判断集合是否为空

    public boolean isEmpty() {

    //如果集合大小为0则返回true

        return size() == 0;

    }

    通过这个集合的迭代器进行遍历,

    按照equals()方法进行判断给定元素是否

    在此集合中

     * @throws ClassCastException

     * @throws NullPointerException

     */

    public boolean contains(Object o) {

        //获取集合的迭代器

        Iterator it = iterator();

        //如果o为null,并且集合含有

        null元素,则返回true,表示含有元素o

        if (o==null) {

            while (it.hasNext())

                if (it.next()==null)

                    return true;

        }

        //如果o不为null,

        则根据equals方法进行相等的判断

         else {

            while (it.hasNext())

                if (o.equals(it.next()))

                    return true;

        }

        //否则该集合中不含有元素o

        return false;

    }

    通过集合的迭代器按顺序返回包含

    集合中所有元素的数组,

    返回的数组长度与迭代器中返回的元素

    个数相等,即使在此方法调用时有别的线程更改了

    集合(也就是不是线程安全的)

    public Object[] toArray() {

       //建立一个与此集合大小相等的数组

        Object[] r = new Object[size()];

        //迭代器

        Iterator it = iterator();

        //遍历复制

        for (int i = 0; i < r.length; i++) {

            if (! it.hasNext())

            //调用Arrays中的静态复制方法copyOf

            第一个参数为要复制的数组

            第二个参数为要复制的长度

            Arrays是集合框架中的工具类

            提供了很多实用的静态方法

            后面会提到

                return Arrays.copyOf(r, i);

            //把每个元素放在数组r中

            r[i] = it.next();

        }

        //这时候就发生不一致了

        证明在这个方法调用时

        这个集合又添加了元素

        导致迭代器中的元素个数

        与size()返回个数不同

        需要特殊处理一下

        其中的方法在后面定义

        finishToArray(r, it)

        表示彻底复制

        return it.hasNext() ? finishToArray(r, it) : r;

    }

    同上一个方法只不过这个方法

    指定了返回数组的类型

     * @throws ArrayStoreException  

     * @throws NullPointerException

     */

    public T[] toArray(T[] a) {

        int size = size();

        //通过Java的反射机制

        创建一个指定类型的数组

        反射后面会提到

        如果数组a的长度大于size()

        则用a就行

        否则创建一个指定类型且大小为size()

        的数组

        T[] r = a.length >= size ? a :

                  (T[])java.lang.reflect.Array

                  .newInstance(a.getClass().getComponentType(), size);

        Iterator it = iterator();

        for (int i = 0; i < r.length; i++) {

        //这段的意思是当迭代器中没有了

        下一个元素,若数组太大

        则将后面所有元素置为null

        否则返回数组

            if (! it.hasNext()) { 

                if (a == r) {

                    r[i] = null;

                } 

                else if (a.length < i) {

                    return Arrays.copyOf(r, i);

                }

                 else {

                    System.arraycopy(r, 0, a, 0, i);

                    if (a.length > i) {

                        a[i] = null;

                    }

                }

                return a;

            }

            //将元素经过类型转换

            放到数组中

            r[i] = (T)it.next();

        }

        //同上一个方法中的情况

        return it.hasNext() ? finishToArray(r, it) : r;

    }

    分配数组能达到的最大个数

    有些虚拟机对于每个数组最大能多大有限制

    强行分配会抛出OutOfMemoryError异常

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 

     重新分配数组,将迭代器剩余元素放入数组中

    private static T[] finishToArray(T[] r, Iterator> it) {

    //作为循环变量使用

        int i = r.length;

        while (it.hasNext()) {

        //进行扩容

            int cap = r.length;

            if (i == cap) {

            //cap>>1:右移操作相当于除以2

                int newCap = cap + (cap >> 1) + 1;

                //若分配的太大了则

                尽最大能力分配

                if (newCap - MAX_ARRAY_SIZE > 0)

                    newCap = hugeCapacity(cap + 1);

                r = Arrays.copyOf(r, newCap);

            }

            //复制迭代器中剩余的元素

            r[i++] = (T)it.next();

        }

        //将多分配的去掉

        return (i == r.length) ? r : Arrays.copyOf(r, i);

    }

    尽最大努力分配的方法

    private static int hugeCapacity(int minCapacity) {

    //小于0抛出异常

        if (minCapacity < 0) 

            throw new OutOfMemoryError

                ("Required array size too large");

    //在Integer.MAX_VALUE和 MAX_ARRAY_SIZE

    中选一个最大值

        return (minCapacity > MAX_ARRAY_SIZE) ?

            Integer.MAX_VALUE :

            MAX_ARRAY_SIZE;

    }

2.定义操作

    //未实现的add()方法

     * @throws UnsupportedOperationException

     * @throws ClassCastException

     * @throws NullPointerException

     * @throws IllegalArgumentException

     * @throws IllegalStateException 

     */

    public boolean add(E e) {

        throw new UnsupportedOperationException();

    }

    如果集合中含有指定元素,

    用iterator中的remove()方法删除

    若iterator中没实现remove()抛出
    UnsupportedOperationException异常

     * @throws UnsupportedOperationException 

     * @throws ClassCastException           

     * @throws NullPointerException    

     */

    public boolean remove(Object o) {

    //迭代器

        Iterator it = iterator();

        //若o为null同样找null

        用迭代器的remove()方法

        删除元素

        if (o==null) {

            while (it.hasNext()) {

                if (it.next()==null) {

                    it.remove();

                    return true;

                }

            }

        }

        //不为null用equals()判断

         else {

            while (it.hasNext()) {

                if (o.equals(it.next())) {

                    it.remove();

                    return true;

                }

            }

        }

        //没找到

        return false;

        从代码上来看若含有多个指定

        元素,只删除最先碰到的那个

    }

    3.批量操作

     * @throws ClassCastException 

     * @throws NullPointerException

    public boolean containsAll(Collection> c) {

    遍历用contains()方法判断

        for (Object e : c)

            if (!contains(e))

                return false;

        return true;

    }

    遍历加入,若没实现add()方法抛出

    UnsupportedOperationException异常

     * @throws UnsupportedOperationException

     * @throws ClassCastException

     * @throws NullPointerException

     * @throws IllegalArgumentException

     * @throws IllegalStateException

    public boolean addAll(Collection extends E> c) {

    //是否添加成功的标志

        boolean modified = false;

        for (E e : c)

            if (add(e))

                modified = true;

        return modified;

    }

    遍历指定集合,若此集合中含有

    指定集合中的元素

    用Iterator的remove()方法删除
    此集合中相应的元素

     * @throws UnsupportedOperationException

     * @throws ClassCastException 

     * @throws NullPointerException 

    public boolean removeAll(Collection> c) {

     //Objects:JDK7新增工具类

     判断指定集合是否存在

        Objects.requireNonNull(c);

        //是否删除成功标志

        boolean modified = false;

        Iterator> it = iterator();

        while (it.hasNext()) {

        //含有则删除

            if (c.contains(it.next())) {

                it.remove();

                modified = true;

            }

        }

        //是否删除成功

        return modified;

    }

    用此集合的迭代器遍历

    若元素在指定集合中不存在则删除

     *

     * @throws UnsupportedOperationException

     * @throws ClassCastException

     * @throws NullPointerException

    public boolean retainAll(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;

    }

    遍历,依次删除元素

     * @throws UnsupportedOperationException {@inheritDoc}

     */

    public void clear() {

        Iterator it = iterator();

        while (it.hasNext()) {

            it.next();

            it.remove();

        }

    }

    重写toString()方法

    按顺序返回[元素1, 元素2, ..]

    这种格式的字符串

    public String toString() {

        Iterator it = iterator();

        if (! it.hasNext())

            return "[]";

        StringBuilder sb = new StringBuilder();

        sb.append('[');

        for (;;) {

            E e = it.next();

            //若集合将自身作为了一个

            元素加入了自己中,则和集合自身

            相同的元素全部用(this Collection)

            表示(类似数据结构中的广义表)

            sb.append(e == this ? "(this Collection)" : e);

            if (! it.hasNext())

                return sb.append(']').toString();

            sb.append(',').append(' ');

        }

    }

}

三.LIst

5e79fd1a47f66dbf2b7ec0b5059df9f8.png 

等候结账的排成长队的一群人,书桌上堆放整齐的一摞书.就是直观的线性表的概念.线性表强调元素之间的顺序,在线性表中只要我知道第i个位置,一定就能找到第i+1个位置,元素是一个挨着一个的.就像数学中y=a*x+b上的点.因为y=a*x+b称为线性函数.所以这种结构才会取名为线性表.描述数据之间具有的线性关系.而在树或图这种不具有线性关系的结构中,第i+1个位置往往是按照某种事先的约定得到的,第i+1个元素是不确定的.java中为表示线性表,引入List接口.根据具体功能着眼点的不同有不同的实现类.List继承自Collection接口.允许元素重复,可以按位置访问元素.定义了基础的线性表必须含有的方法.不同子类进行各自的拓展.
Collection中具有的方法将不再重复说明

public interface List extends Collection {

    1.查询操作

    int size();

    boolean isEmpty();

    boolean contains(Object o);

    Iterator iterator();

    Object[] toArray();

    T[] toArray(T[] a);

    2.定义操作

    在List末尾添加元素

     * @param e 添加的元素

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

    boolean add(E e);

    删除第一个查找到的元素

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws UnsupportedOperationException 

    boolean remove(Object o);

    3, 批量修改

     * @throws ClassCastException 

     * @throws NullPointerException 

     * 参见contains(Object)

     */

    boolean containsAll(Collection> c);

    添加到末尾

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException i

     * 参见 add(Object)

     */

    boolean addAll(Collection extends E> c);

    将集合插入到List的指定位置,原位置和原位置后的元素后移

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

     * @throws IndexOutOfBoundsException

        若指定的位置越界

    boolean addAll(int index, Collection extends E> c);

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * 参见 remove(Object)

     * 参见 contains(Object)

     */

    boolean removeAll(Collection> c);

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * 参见 remove(Object)

     * 参见 contains(Object)

     */

    boolean retainAll(Collection> c);

    将List中的所有元素替换为执行特定操作后的结果

     从 JDK1.8开始支持default

    default void replaceAll(UnaryOperator operator) {

        Objects.requireNonNull(operator);

        final ListIterator li = this.listIterator();

        while (li.hasNext()) {

            li.set(operator.apply(li.next()));

        }

    }

    按指定规则排序

    default void sort(Comparator super E> c) {

        Object[] a = this.toArray();

        Arrays.sort(a, (Comparator) c);

        ListIterator i = this.listIterator();

        for (Object e : a) {

            i.next();

            i.set((E) e);

        }

    }

    清空

     * @throws UnsupportedOperationException 

    void clear();

    4.比较和哈希

    元素相同并且位置相同返回true

    boolean equals(Object o);

    哈希函数为

         int hashCode = 1;

         for (E e : list)

            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

     保证了若equals()则哈希值相同

     * @return List的哈希值

    int hashCode();

    5,对于元素索引的操作

    返回指定位置上的元素

     * @param index 位置

     * @throws IndexOutOfBoundsException 位置越界

    E get(int index);

    用新元素代替指定位置上的元素

     * @param index 位置

     * @param element 相应位置上的新元素

     * @throws UnsupportedOperationException i

     * @throws ClassCastException 

     * @throws NullPointerException i

     * @throws IllegalArgumentException 

     * @throws IndexOutOfBoundsException 

    E set(int index, E element);

    在指定位置插入新元素,此位置上和此位置后面

    的元素以此右移,注意和set()的区别

     * @throws UnsupportedOperationException i

     * @throws ClassCastException

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

     * @throws IndexOutOfBoundsException 

    void add(int index, E element);

   删除指定位置的元素,后面的元素左移

     * @throws UnsupportedOperationException 

     * @throws IndexOutOfBoundsException 

    E remove(int index);

    6,查找操作

    返回第一次查找到元素的位置,没有返回-1

     * @throws ClassCastException 

     * @throws NullPointerException 

    int indexOf(Object o);

    返回最后一次查找到元素的位置,没有返回-1

     * @throws ClassCastException 

     * @throws NullPointerException 

    int lastIndexOf(Object o);

    7,线性表的迭代器

    按当前线性表的顺序返回一个迭代器

    ListIterator listIterator();

    从制定位置返回迭代器,包含index位置上的元素

    ListIterator listIterator(int index);

    8,分解线性表

    返回指定起始位置到指定结束位置-1之间的元素

     * @param fromIndex 起始位置

     * @param toIndex 结束位置

     * @return 以List形式返回

     * @throws IndexOutOfBoundsException 

    List subList(int fromIndex, int toIndex);

四.set

 d948ea3452b4284f571c4f2950ad3662.png

 Set就是普通的数学概念上的集合提到集合,有个很有意思的哥德尔定理.哥德尔证明了任意一个公理系统相容性跟完备性是不能同时存在的即你希望一个系统相容,就是没有互相矛盾的命题,那么这个系统肯定不是完

备的,就是无法涵盖这个公理系统所能描述的全部命题.

相反你的公理系统能描述你所研究的问题的所有命题.那么肯定有些命题是互相矛盾的.我感觉他确定了这个世界上不会存在完美的事物.你每解决一个问题,就会创造出更多的问题.

Set不允许有相同的元素,即使是null元素也只能允许有一个基于普通equals()方法判断两个元素是否相等,你如果重写equals()破坏规则,那Set中就可以加入 重复元素.但那样Set会失它自身作为一种特殊结构的意义

public interface Set extends Collection {

    Collection中重复的方法

    不再说明

    1.查询操作

    int size();

    boolean isEmpty();

    boolean contains(Object o);

    返回不保证元素顺序的迭代器

    Iterator iterator();

    Object[] toArray();

    T[] toArray(T[] a);

    2.定义操作

    将集合中不含有的元素

    加入集合

    boolean add(E e);

    boolean remove(Object o);

    3.批量操作

    boolean containsAll(Collection> c);

    若集合中不存在

    指定集合c中的某个元素

    将此元素加入集合

    并集

    boolean addAll(Collection extends E> c);

    交集

    boolean retainAll(Collection> c);

    差集

    boolean removeAll(Collection> c);

    void clear();

    4.比较和哈希

    两个集合有相同的大小,

    元素相同返回true

    boolean equals(Object o);

    int hashCode();

   并行迭代器

   从JDK1.8开始

   (我还没研究,不怎么了解)

    default Spliterator spliterator() {

        return Spliterators.spliterator(this, Spliterator.DISTINCT);

    }

}

五.queue

 03af5dcb7368be2430779910683019db.png

 
观察超市排列整齐(不整齐大致是这个形状也行

强迫症不要纠结)的一个等待结账的长队,

约定:把靠近收银员的第一个人的位置称为队首,

沿着队首一个人一个人的向后走(也就是线性的)最后一个人

的位置称为队尾

我们会发现:

1.最后来的人(如果他有素质不插队)

总是在队尾的位置等候

(因为每再来一个人,它就站在了队尾的位置上

原先站在队尾位置上的人站在他的前面)

2.收银员总是为队首的人进行服务

如果一堆数据之间的关系呈现出上面所说的形状,并

具有上面所说的性质.则把这堆数据

组织起来的结构称为队列.

很明显队列是前面所说的List(线性表)

的一种,但是Java把它从List的继承体系中

单独拿了出来做为一个接口,直接继承

Collection接口而不是List接口

队列在计算机中也用一个稀奇古怪的

名称呼FIFO计算机中总是有这种稀奇古怪的

名其实他们都是单词的缩写,尤其是网络中更多

FIFO:first in first out

字面理解:先进先出

我比你先排队,我肯定比你先结账.

从服务性质上来说,队列体现了基于时间

的公平性.

但是假如有个人,他手中拿着一把枪

对排在队列中的人说

"让开,老子要站在你前面!"

(假如他想站在后面也行)

被威胁的那个人一定会乖乖让开,

因为他手里没枪.

为了描述这种现象,计算机中

引入了优先队列的概念,优先队列虽然

跟队列沾边,但是它破坏了队列FIFO的

性质.因为现在是谁手里有枪谁说了算,

不再是基于时间公平服务了.他手里那把枪

计算机称为优先级,优先级是一个具体的数字.

它的大小决定了服务的顺序.

假设枪的优先级为10,所有人的优先级初始

为0,有枪的人就会+10,收银员肯定是挑优先级最大

的人先服务.

Java中还有一种队列叫阻塞队列在

java.util.concurrent.BlockingQueue中

它继承了这个接口.阻塞队列是为了多线程之间

同步用的

public interface Queue extends Collection {

    把一个元素加入到队列中

     因为有好几种队列,所以没说一定加到队尾

    添加成功返回true

     * @throws IllegalStateException 队列没有足够的地方装

     这个元素了 

     * @throws ClassCastException 

     * @throws NullPointerException 元素为空,但是

     队列禁止加入空元素

     * @throws IllegalArgumentException 

    boolean add(E e);

    同样是添加元素,add()当容量不足

    装不下新元素时抛出异常,

    但这个方法返回false

    @throws ClassCastException 

    @throws NullPointerException 

    @throws IllegalArgumentException 

    boolean offer(E e);

   删除队首元素,并返回

     * @throws NoSuchElementException 队列为空,你还想删除

     就抛出这个异常

    E remove();

   删除队首元素并返回队首值

  只是 队列为空就返回null

    E poll();

   获取队首值
  没有时抛出异常

     * @throws NoSuchElementException 

    E element();

    获取队首值没有时
   返回null

    E peek();

}

六.dequeue

同样是上文那个超市队列

约定:

1.最后来的人站在队尾的位置

这个动作叫做插入

2.队首的人结完账离开叫做删除

则普通的FIFO队列仅支持队首删除,

队尾插入

deque:double ended queue

常被称作双端队列,

因为它允许在队列的两端都可以进行

插入,删除操作

可被用作栈,不支持像List一样按

索引取元素,

支持插入null元素

从JDK1.6开始支持

public interface Deque extends Queue {

    1.作为双端队列

     在队首的位置插入元素

     * @throws IllegalStateException 容量限制,限制不能插入

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

    void addFirst(E e);

    在队尾插入元素

     * @throws IllegalStateException 同样,下面不写了

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

    void addLast(E e);

    同样是队首插入,没地方不抛出异常

    只是返回false,代表插入失败

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException

    boolean offerFirst(E e);

    一样的

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException 

    boolean offerLast(E e);

    删除队首元素,返回队首值

     * @throws NoSuchElementException 队列为空,你还想删除

     抛出这个异常

    E removeFirst();

    一样的(因为是双端队列吗,很多操作是对称的,只是一个在队首

    另一个在队尾)

     * @throws NoSuchElementException 

    E removeLast();

    也是删除队首,返回队首值但队列为空时返回null

    不抛出异常

    E pollFirst();

   在队尾的对称方法

    E pollLast();

    获取队首值,但是不删除队首

     * @throws NoSuchElementException 队列为空

    E getFirst();

     * @throws NoSuchElementException 队列为空

    E getLast();

   获取队首,但是队列为空时返回null

    E peekFirst();

    E peekLast();

    原文没说按那个顺序删除,

    应该是从队首到队尾的顺序,

    删除碰到的第一个指定的元素

     * @throws ClassCastException 基于比较的方法中抛出这个异常

     都是因为集合中的元素,和指定的元素无法比较

     * @throws NullPointerException 

    boolean removeFirstOccurrence(Object o);

    这是删除最后碰到的

     * @throws ClassCastException 

     * @throws NullPointerException 

    boolean removeLastOccurrence(Object o);

    2.作为普通队列

    按理来说这些方法它的父类中都有

    没必要放在这

    但Java允许把deque当作普通队列来用

    放在这向上转型时会优先调用这里的方法

    这里的插入明确指定插入到队尾

    Queue中不强调位置

    剩下的一样

    add()抛出异常

    offer()返回false

    boolean add(E e);

    boolean offer(E e);

    E remove();

    E poll();

    E element();

    E peek();

    3.作为栈

    压栈

     * @throws IllegalStateException 容量不足

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException i

    void push(E e);

    出栈

     * @throws NoSuchElementException 栈为空

    E pop();

   4.作为普通集合的方法

    跟removeFirstOccurrence(Object)一样

     * @throws ClassCastException 

     * @throws NullPointerException 

    boolean remove(Object o);

    判断是否含有指定元素

     * @throws ClassCastException 用到比较而两个元素不可

     比较时,抛出这个异常

     * @throws NullPointerException 

    boolean contains(Object o);

    队列大小

    public int size();

   按照从队首到队尾的顺序返回队列的迭代器

    Iterator iterator();

    按照从队尾到队首的顺序返回队列的迭代器

    Iterator descendingIterator();

}

七.iterator

AbatractCollection中多次用

到了迭代器,那么迭代器是什么.

某个集合的迭代器保管了这个集合

的所有元素,提供遍历这些元素的方法

你想要下一个元素告诉迭代器

next()它就给你当前元素的下一个元素

你想知道迭代器中是否还有元素

你问迭代器hasNext()它会告诉你结果

迭代器说白了就是一个for循环

那么为什么不用for循环非得发明

个迭代器呢

设计模式中有一种就是迭代器模式

详情参见

http://www.runoob.com/design-pattern/iterator-pattern.html

这些是普遍说的优点:

1、它支持以不同的方式遍历一个聚合对象.

因为你可以自己写不同的for循环吗,感觉不是什么优点

2、迭代器简化了集合类

感觉没简化,只是以前用for循环写的

现在都通过一个迭代器返回.代码量

不会变的,可能反倒增多.

3、在同一个集合上可以有多个遍历.

这倒是真的,因为你可以返回多个

迭代器

4、在迭代器模式中,增加新的集合类和

迭代器类都很方便,无须修改原有代码。

这更扯淡,他说的无须修改原有代码,

其实是修改不了,新的集合类肯定有不同于

原有集合类的特点,要不然你创建它干嘛,

迭代器也肯定得重写.

5.用于顺序访问集合对象的元素,不需要

知道集合对象的底层表示。

如果你只是简单的遍历,当然不需要知道集合对象的

底层表示,因为集合类已经帮你实现完了.

但很少只是简单遍历,你要在遍历中对对象进行处理,

还是得知道存的对象是什么.有时候还

经常强制类型转换.但是迭代器确实隐藏了底层

具体用什么存储这些对象的细节.是数组啊,还是链表啊

或是队列.

我感觉为什么需要这个迭代器是

因为每一种集合你肯定会有对它遍历的

需求.每个集合中都得有for循环.那干脆将

这些for提取出来由另一个统一的概念来表达.

你的程序中如果有大段大段的重复代码,

你肯定会将它抽离为一个函数(方法).

而不是每次需要这段逻辑的时候,

都得没完没了的重写一次,即使有

ctrl+c也很麻烦.

提到迭代器Iterator还有一个东西Enumeration(枚举类)

它也是遍历用的

区别是:

Enumeration是JDK 1.0添加的接口。

使用到它的函数包括Vector、Hashtable等类,

这些类都是JDK 1.0中加入的,

Enumeration存在的目的就是为它们提供遍历

接口。Enumeration本身并没有支持同步,

而在Vector、Hashtable实现Enumeration时,

添加了同步。

Iterator是JDK 1.2才添加的接口,

它也是为了HashMap、ArrayList等集合提供遍历接口。

Iterator是支持fail-fast机制的:

当多个线程对同一个集合的内容进行操作时,

就可能会产生fail-fast事件。

fail-fast事件指的是假如当某一个线程A

正在通过iterator去遍历某集合,若该集合

的内容被B线程改变了;那么线程A访问集合时,

立即抛出ConcurrentModificationException异常,

所说的fail-fast事件。

因为Iterator支持这种机制它自然要付出时间的

代价,用它俩同时遍历一个能用这俩同时遍历的

集合Enumeration肯定会更快

public interface Iterator {

    //迭代器中是否还有元素

    boolean hasNext();

    //返回迭代器中的下一个元素

     * @throws NoSuchElementException 迭代器中没有下一个元素了

    E next();

    删除元素

     * @throws UnsupportedOperationException 

     * @throws IllegalStateException 

     你没调用过next()直接就执行remover()就抛出这个异常

    default void remove() {

        throw new UnsupportedOperationException("remove");

    }

    用指定的动作检查迭代器中剩余的元素,

    支持fail-fast

     * @throws NullPointerException 指定的检查动作为空

    default void forEachRemaining(Consumer super E> action) {

        Objects.requireNonNull(action);

        while (hasNext())

            action.accept(next());

    }

}

八.listiterator

继承自Iterator接口,只适用于线性表的迭代器

Iterator接口只允许从开头到结尾按这个顺序

进行迭代遍历

ListIterator允许你在当前位置向前或向后,还可以获取位置,
它不指向任何一个元素,ListIterator的指针

(这里的指针不是内存地址那个指针,是遍历时候对于位置的

一个标记,原文单词是 cursor:游标(数据库中) 光标(用户界面中) 指针(程序中)的意思)

永远在两个元素之间.(所以你才能获取前一个,或后一个)

JDK中还用图大概表示了这个概念

元素: Element(0) Element(1) ... Element(n-1)

指针:^                  ^                  ^                          ^

set()和remove()方法不是改变指针的

还是改变元素的

public interface ListIterator extends Iterator {

    1.查询操作

    指针后面是否还有元素

    boolean hasNext();

    返回下一个元素,指针右移(后移)

     * @throws NoSuchElementException 

    E next();

    指针前面是否有元素

    boolean hasPrevious();

    返回前一个元素,指针左移(前移)

    E previous();

    返回后一个元素的索引(注意索引从0开始)

    若此时指针到达最后一个元素的后面,

    调用时返回集合的长度

    int nextIndex();

    返回前一个元素的索引

    若此时指针在第一个元素前

    调用时返回-1

    int previousIndex();

    2.定义操作

    删除操作

      @throws UnsupportedOperationException 

      @throws IllegalStateException 

     你没调用过next()或previous()直接就

     调用remover()就抛出

      IllegalStateException异常

    void remove();

    把按照next()或previous()顺序返回的当前

    (注意是当前)元素设置为另一个值

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws IllegalArgumentException 

     * @throws IllegalStateException 你没调用过next()

     或previous()或者当前指针已经在最后一个元素后面了

     就抛出这个异常.(就是因为Java不知道你要设置那个元素的值)

    void set(E e);

    插入一个元素

    这个元素的位置在你没插入之前调用next()方法返回的元素之前

    (原文中是 would be)

    或者是你没插入之前调用previous()方法返回的元素之后

    (我感觉就是原地插入,指针相应的移动)

     @throws UnsupportedOperationException 

     @throws ClassCastException 

     @throws IllegalArgumentException 

    void add(E e);

}

九.map

 8e2c2aaa03cf2ef8e6c3bc3835d17dd4.png

 Map名词是地图,作为

动词是映射的意思

Map中保存的元素的形式

都是Key/Value(键值对)

的形式

你通过一个Key能找到这个Key

对应的Value.

你可能感觉多次一举,直接存Value

找Value不就行了吗.于是就回到了List

想象这种情况

你在一本很厚的杂志上

发现了一篇写的很好的文章你读完了它

因为写的太好你大概都能背下来了

第二天你还想再看一遍这篇文章

你会怎么做

你会把整本文章都依次的读一遍.

每读完一篇,你比对你记忆中的文章.

发现不是,于是接着读下一篇文章吗.

肯定不是

你会翻到目录,因为你不仅背下了那篇文章

连那篇文章的题目你都知道

你先找那篇题目,目录告诉你在

572页(Key),你立即翻到572页

找到了那篇文章(Value)

计算机把这种想法叫hash(散列)

有时直接用音译哈希

(我以前一直以为哈希是个人名)

用这种想法再看List(线性表)

其实它也是Key/Value映射

只不过Key值是规定从0开始的整数

在List中只能这样存储

文章[572]

但是它那个Key没什么具体意义

没有上下文你怎么知道代表什么

572个字,572元稿费

在Map中你可以这么定义

{我喜欢的文章 在572页->文章}

Map中不允许包含重复的Kye

你们班有两个叫一样名的人,

那他俩名字这个标识作用就失去意义了

一个key只能对应一个Value

你们班没有重名的人,

但是,有一天你叫一个名字,

有两个人喊到

("你是假的"

"你才是假的"

"去如来佛祖那....")

但多个key可以映射到一个

value

你大名叫...

小名叫...

绰号叫...

都是你

 不允许把一个Map自身作为Key

 加入自身中,但是作为Value

 加入自身是可以的.但这时

 equals()和hashcode()就会

 失去意义

 (暂时没理解这句话什么意思

 原文是:

 A special case of this prohibition is that it

 is not permissible for a map to contain itself 

 as a key.While it is permissible for a map to 

 contain itself as a value,extreme caution is

 advised: the equals and hashCode methods are no

 longer well defined on such a map.)

 所有的实现了Map的类必须实现两个构造

 函数,一个是不带参数的构造函数

 用来构造一个空Map,另一个是以Map

 作为参数的构造函数,构造一个包含

 相同key/value的map

 所有不支持的操作都抛出

 UnsupportedOperationException异常

 作为响应

 不允许加入null元素,但你想加入

 null元素,抛出NullPointerException异常

 遍历含有自身的map有的map实现类

 会抛出异常

map是一个独立接口,但它依赖Collection

public interface Map {

    1.查询操作

    返回这个map含有多少个

    键值对

    int size();

    boolean isEmpty();

    是否含有指定得key

     * @throws ClassCastException map中不支持存储这样的key

     * @throws NullPointerException 

    boolean containsKey(Object key

    是否含有指定value

     * @throws ClassCastException 

     * @throws NullPointerException 

    boolean containsValue(Object value);

    返回指定的key对应的value

     * @throws ClassCastException 

     * @throws NullPointerException 

    V get(Object key);

    2.定义操作

    将键值对放入map如果已经存在这个key了

    用新value代替旧的

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException

    V put(K key, V value);

    删除map中包含key的键值对,

    返回删除的key对应的value

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

    V remove(Object key);

   3.批量操作 

   将另一个map加入到此map中

     * @throws UnsupportedOperationException 

     * @throws ClassCastException 

     * @throws NullPointerException 

     * @throws IllegalArgumentException

    void putAll(Map extends(这个extends保证了它是K,或K的子类) K, ? extends V> m);

    void clear();

4.视图

    (原文是Views,

    没想到更好的名称)

    以set的形式返回此map中

    所有的key,这个set依赖于map

    你在map中改动,会反应到set上

    Set keySet();

    以Collection的形式返回此map中

    所有的value,这个Collection依赖

    于map你在map中改动,会反应到

    Collection上

    Collection values();

    以Set的形式返回此map的

    键值对

    Set> entrySet();

    存放键值对的实体

    在接口中定义接口

    就像在类中定义类

    逻辑上的包含

    没有任何访问权限关键字

    证明仅包级可见

    (不是map包中的你见这个接口有什么用)

    interface Entry {

       返回这个实体对应的key

         * @throws IllegalStateException 你调用的时候

         这个key已经被删除了

        K getKey();

        返回这个实体对应的value

         * @throws IllegalStateException

        V getValue();

        设置这个实体的value

         * @throws UnsupportedOperationException 

         * @throws ClassCastException 

         * @throws NullPointerException 

         * @throws IllegalArgumentException 

         * @throws IllegalStateException 

        V setValue(V value);

        如果两个实体key相等

        value相等则返回true

        boolean equals(Object o);

        返回哈希值保证若equals()

        则哈希值相等

        int hashCode();

        按照key进行比较

         从JDK1.8开始

        public static , V> Comparator> comparingByKey() {

            return (Comparator> & Serializable)

                (c1, c2) -> c1.getKey().compareTo(c2.getKey());

        }

        按value进行比较

        public static > Comparator> comparingByValue() {

            return (Comparator> & Serializable)

                (c1, c2) -> c1.getValue().compareTo(c2.getValue());

        }

       按照指定的规则对key进行比较

        public static Comparator> comparingByKey(Comparator super K> cmp) {

            Objects.requireNonNull(cmp);

            return (Comparator> & Serializable)

                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());

        }

        按指定规则对value进行比较

        public static Comparator> comparingByValue(Comparator super V> cmp) {

            Objects.requireNonNull(cmp);

            return (Comparator> & Serializable)

                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());

        }

    }

    5.比较和哈希

   比较两个map是否相等

    boolean equals(Object o);

    int hashCode();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值