zoukankan      html  css  js  c++  java
  • Java容器解析系列(2) 具体化的第一步——Collection到AbstractCollection

    在通向具体化的List,Queue之前,我们需要先了解一下Collection接口和AbstractCollection抽象类,这两个都是处于Collection顶层的存在.

    Collection接口,是Collection hierarchy的根接口,我们来看其定义了哪些必须实现的方法:

    /**
        Collection接口,是CollectionC hierarchy的根接口。
        一个Collection表示一些元素对象的聚集;
        一些Collection的实现类允许重复的元素对象,另一些不允许;
        一些有序而另一些没有; 
       有些不允许元素为null,试图向其中添加null元素是会抛出非检查时异常;
        Collection实现类是否是同步的取决于其具具体实现;
        Collection并不提供直接的Collection的具体实现类,而是通过一些子接口,如Set和List等。这些接口被用来提供关于聚集操作的更为具体的泛化。
      程序员应当为每一个Collection实现类提供一个无参的构造方法和一个参数为Collection的构造方法;
     * @since 1.2
     */
    public interface Collection<E> extends Iterable<E> {
        int size();
        boolean isEmpty();
        boolean contains(Object o);
        Iterator<E> iterator();
    
        // 以数组的形式返回Collection中所有对象,如果Collection实现类是有序的,返回的该数组也应该同样的有序;
        // 返回的数组必须保证当前Collection对象对该数组没有任何引用,也就是说,应该分配一个新的数组,并把元素填充到该数组中,并返回;
        // 因为是一个新的数组,也就保证了返回的数组是可以被随意修改的,而不会影响到Collection对象(这里其实仅保证修改返回的数组中元素的顺序时不会影响到Collection对象,如果修改数组中某个位置的对象的内容,则Collection中相应的对象内容也会被修改,因为其实是同一个对象,这里的复制为浅复制)
        Object[] toArray();
    
        // 如果传入的数组大小能够容纳Collection中的所有元素,将Collection中的所有元素填入传入的数组中,如果有多余空间,其余的空间都会被置为null;
        // 如果传入的数组空间不够,该方法同toArray()方法;
        // 如果传入的数组元素类型不是集合中元素类型的父类型,抛出ArrayStoreException
        // 如果传入的数组为null,抛出NullPointerException
        <T> T[] toArray(T[] a);
    
        boolean add(E e);
        boolean remove(Object o);
        boolean containsAll(Collection<?> c);
        boolean addAll(Collection<? extends E> c);
        boolean removeAll(Collection<?> c);
    
        // 保留只在当前Collection中存在而在指定Collection中不存在的对象
        boolean retainAll(Collection<?> c);
    
        void clear();
        boolean equals(Object o);
    
        // Collection对hashCode()方法没有特别的规定,但是程序员需要注意,当实现equals()方法时,
        // 应该实现hashCode()方法,因为c1.equals(c2)暗示(imply)了c1.hashCode()==c2.hashCode()
        int hashCode();
    }
    

    从上面的代码可以看出:
    Collection规定了其实现类必须具有增删改查的能力(其中"删"为可选操作);
    其所定义的所有方法都直接或间接为这些功能实现提供服务;

    补充:

    1. Collection规定了实现类判断两个元素相等的方式为 (onull ? enull : o.equals(e))
    2. Collection中的有些方法不一定每个实现类都要实现,包括remove(),removeAll(),add(),addAll(),clear(),retailAll(),这些方法称为可选操作(optional operation),且都与删除元素有关;如果实现类决定不实现该方法时,应默认抛出UnsupportedOperationException;

    为什么要有可选操作:
    防止在设计中出现接口爆炸的情况,避免为了各种特例单独定义接口
    也就是说,如果没有这些可选操作,那么为了限制一些类不支持这些操作,我们需要再定义一个接口,这种情况下假设叫"NoOpionalCollection";
    在Java集合中,有很多地方有可选操作这种需求(比如要有一个集合类不允许添加元素,一个集合类不允许修改元素,一个集合类不允许删除元素),如果为这些特殊需求每个都设计一个接口,那么就有,UnModifiableCollection,UnAddCollection等,这是完全没有必要的;而如果有这些可选操作,如果不支持这个操作,直接抛出异常即可;

    接下来我们将目光再往下看,AbstractCollection在Collection的基础上添加了哪些具体实现:

    /**
     * @since 1.2
     */
    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 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() {
            // Estimate size of array; be prepared to see more or fewer elements
            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;
        }
    
        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;
        }
    
        // Modification Operations
    
        public boolean add(E e) {
            throw new UnsupportedOperationException();
        }
    
        // 默认通过Iterator来检索,删除指定元素
        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 void clear() {
            Iterator<E> it = iterator();
            while (it.hasNext()) {
                it.next();
                it.remove();
            }
        }
    
    
        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);
                if (! it.hasNext())
                    return sb.append(']').toString();
                sb.append(',').append(' ');
            }
        }
    
    }
    

    可以看出,AbstractCollection提供了一个Collection集合实现及基本骨架,为进一步实现,指明了方向:

    1. 实现一个不可变的Collection,只需要继承该类并实现iterator()和size(),并且对iterator()返回的Iterator实现hasNext()和next();
    2. 实现可变的Collection,还需要实现add()方法,并对iterator()方法返回的Iterator实现remove()方法;
    3. AbstractCollection中几乎所有默认的操作,都是通过Iterator来实现的;
    Let's go change the world,or changed by the world
  • 相关阅读:
    React元素渲染
    初识JSX
    微信小程序复制文本到剪切板
    微信小程序报错request:fail url not in domain list
    小程序,通过自定义编译条件,模拟推荐人功能
    积分抵扣逻辑
    微信小程序 switch 样式
    tomcat 配置开启 APR 模式
    tomcat8 传输json 报错 Invalid character found in the request target. The valid characters are defined in RFC 3986
    c++数组初始化误区
  • 原文地址:https://www.cnblogs.com/jamesvoid/p/9779114.html
Copyright © 2011-2022 走看看