java集合系列03 AbstractCollection

来源:互联网 发布:mac官网 编辑:程序博客网 时间:2024/06/05 08:07

上篇介绍了Collection接口的定义,这篇我们介绍一下AbstractCollection,
此抽象类对Collection接口定义的大多数方法提供了具体的实现。

首先先放一张uml图
uml

接下来看一看文档对该类的大体介绍

此类提供了对Collection接口的大体实现,来使编程人员实现Collection接口付出最小的努力
要实现一个不可变集合,编程人员只需要提供iterator()和size()方法的实现
要实现一个可变集合,编程人员必要额外的覆盖此类的add方法,iterator()方法返回的迭代器必须额外实现其remove()方法
编程人员需要提供一个无参构造器和一定指定集合接口的有参构造器

下面我们来分析的具体的代码

public abstract class AbstractCollection<E> implements Collection<E>{    protected AbstractCollection(){    }    //抽象方法等待非抽象子类提供具体的实现    public abstract Iterator<E> iterator();    public abstract int size();    //判断此集合是否为空    public boolean isEmpty(){        return size() == 0;    }
//添加元素的方法,需要子类自己实现public boolean add(E e){    throw new UnsupportedOperationException();}
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 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 contains(Object o){    Iterator<E> it = iterator();    while(it.hasNext()){        return (o == null ? it.next() == null : o.equals(it.next()))    }}public boolean remove(Object o){    Iterator<E> it = iterator();    while(it.hasNext()){        if(o == null ? it.next() == null : o.equals(it.next()){            it.remove();            return return;        }    }}

跟据我的分析 下面的这段代码每次循环都要判断 o == null 虽然代码很简洁但是多了很多不必要的判断,而JDK源码只需要判断一次 o == null 所以 JDK源码里的效率要高。

批量操作

//实现上就是迭代并调用contains(Object e)方法public boolean containsAll(Collection<?> c){    for(Object e : c){        if(!contains(e)){            return false;        }    }    return true;}//迭代并调用add(E e)方法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){    //一个工具类,有兴趣的同学可以研究一下    Objects.requireNonNull(c);    boolean modified = false;    Iterator<?> it = iterator();    while(it.hasNext()){        if(c.contains(it.next())){            it.remove();            modified = true;        }    }    return modified;}//保留两个集合相同的元素 //retainAll 和 removeAll 两个方法的代码的为一差别在于对c.contains(it.next())的决断public boolean retainAll(Coollection<?> c){    Objects.requireNonNull(c);    boolean modified = false;    Iterator<E> it = iterator();    while(it.hasNext()){        if(!c.contains(it.next())){            it.remove();            modified = true;        }    }    return modifed;}//public void clear(){    Iterator<E> it = iterator();    while(it.hasNext()){        it.next();        it.remove();    }}

比较有意思的toString方法

public String toString(){    Iterator<E> it = iterator();    //判断集合是否为空    if(!it.hasNext()){        return "[]";    }    StringBuilder sb = new StringBuilder();    sb.append('[');    for(;;){        E e = it.next();        //判断元素是否是集合本身,如果是追加字符串(避免无限递归)        sb.append(e == this ? "(this Collection)" : e);        //如果没有下一个元素了追加']'并返回sb.toString()        if(!it.hasNext()){            return sb.append(']').toString();        }        //如果不是集合的最后一个元素,追加", "        sb.append(',').append(' ');}

类似的代码还在Arrays.toString(Object[] a)里出现了类似的代码

public static String toString(Object[] a){    if(a == null){        return "null";    }    int iMax = a.length - 1;    if(iMax == -1){        return "[]";    }    StringBuilder b = new StringBuilder();    b.append('[');    for(int i =0; ; i++){        b.append(String.valueOf(a[i]));        if(i == iMax)            return b.append(']').toString();        b.append(", ");    }}

如果要你实现这个toString()方法,你该怎么实现呢。以我的思路,我会利用size() 和 iterator()方法吧(思路和AbstractCollection.toString()差不多,看来我的思路被限制住了)。

public String toString(){    int size = size();    if(size == 0){        return "[]";    }    Iterator<E> it = iterator();    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(' ');    }}

最后是集合转换数组的两个方法,比较难理解,也是此篇文章打算重点介绍的吧

//用于分配数组的最大容量,因为有些虚拟机在数组存储一些头信息。//试着存储更大数组会造成OutOfMemoryError异常private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//最大的容量private static int hugeCapacity(int minCapacity){    if(minCapacity < 0){        throw new OutOfMemoryError("Required array size too large");    }    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE :        MAX_ARRAY_SIZE;}private static <T> T[] finshToArray(T[] r, Iterator<?> it){    int i = r.length; //准备数组的索引;    while(it.hasNext()){ //如果迭代器有下一个元素        int cap = r.length; //数组的容量        if(i == cap){ //如果数组的索引 与 数组的容量 相等 将数组扩容            int newCap = cap + (cap >> 1) + 1; //新的容量            if(newCap - MAX_ARRAY_SIZE > 0){ //检测新的容量 是否大于数组容量的最大值                          newCap = hugeCapacity(cap + 1);//如果大于,新的容量就等于最大的容量            }            r = Arrays.copfy(r, newCap); //将数组扩容        }        r[i++] = (T)it.next(); 将迭代器返回的元素追加到数组的索引位置    }    return (i == r.length) ? r : Arrays.copyOf(r, i); //返回一个新的不含多余容量的数组}//返回包含此collection中所有元素的数组。如果collection的迭代器返回的元素是有序的,那么此数组也应该是有序的。//返回的数组将是安全的,也就是说会返回一个新的数组,所以可以随意修改返回的数组。//此方法充当了基于数组的API与基于collection的API之间的桥梁//此实现返回一个数组,它包含此 collection 的迭代器返回的所有元素,这些元素的排列顺序与数组的连续元素存储顺序相同,都是从索引 0 开始。返回数组的长度等于迭代器返回的元素数,即使此 collection 的大小发生更改也是如此,这种情况可能发生在 collection 允许在迭代期间进行并发修改时。size 方法只是作为一个优化提示被调用;即使迭代器返回不同的元素数,也会返回正确的结果。public Object[] toArray(){    Object[] r = new Object[size()]; //新建一个与集合size相等的数组    Iterator<E> it = iterator();    for(int i = 0; i < r.length; i++){         if(! it.hasNext()){ //如果期待的数量> 迭代器返回元素的数量            return Arrays.copyOf(r, i); //将数组减容,并返回        }        r[i] = it.next(); //将迭代器返回的元素添加到数组的当前索引    }    return it.hasNext() ? finishToArray(r, it) : r; //检测迭代器有没有下一个元素如果有调用finishToArray方法。}
0 0
原创粉丝点击