JAVA集合

本文深入解析Java集合框架,包括Collection、List、Set等接口及其实现原理,探讨各种集合类如ArrayList、LinkedList的特点与应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下,结合源码分析集合类所有集合数据结构对接口。以JDK1.8为准。

a2.jpg

1. Collection

int size()
//返回此 collection 中的元素数。
//如果此 collection 包含的元素大于 Integer.MAX_VALUE,则返回 Integer.MAX_VALUE。

boolean isEmpty()
//如果此 collection 不包含元素,则返回 true。 

boolean contains(Object o)
//当且仅当此 collection 至少包含一个满足 (o==null ? e==null : o.equals(e)) 的元素 e 时,返回 true。 

Iterator<E> iterator()
//返回在此 collection 的元素上进行迭代的迭代器。
//关于元素返回的顺序没有任何保证,除非此 collection 是某个能提供保证顺序的类实例。 

Object[] toArray()
//返回包含此 collection 中所有元素的数组。
//如果 collection 对其迭代器返回的元素顺序做出了某些保证,那么此方法必须以相同的顺序返回这些元素。 
//返回的数组将是“安全的”,因为此 collection 并不维护对返回数组的任何引用。
//调用者可以随意修改返回的数组。 
//此方法充当了基于数组的 API 与基于 collection 的 API 之间的桥梁。 

boolean add(E e)
//确保此 collection 包含指定的元素。如果此 collection 由于调用而发生更改,则返回 true。
//如果此 collection 不允许有重复元素,并且已经包含了指定的元素,则返回 false。

boolean remove(Object o)
//如果此 collection 包含一个或多个满足 (o==null ? e==null : o.equals(e)) 的元素 e,则移除这样的元素。
//如果此 collection 包含指定的元素(或者此 collection 由于调用而发生更改),则返回 true 。 

boolean containsAll(Collection<?> c)
//如果此 collection 包含指定 collection 中的所有元素,则返回 true。 

boolean addAll(Collection<? extends E> c)
//将指定 collection 中的所有元素都添加到此 collection 中。
//如果在进行此操作的同时修改指定的 collection,那么此操作行为是不确定的。

boolean removeAll(Collection<?> c)
//移除此 collection 中那些也包含在指定 collection 中的所有元素。
//此调用返回后,collection 中将不包含任何与指定 collection 相同的元素。 

void clear()
//移除此 collection 中的所有元素。

boolean retainAll(Collection<?> c)
//仅保留此 collection 中那些也包含在指定 collection 的元素。
//移除此 collection 中未包含在指定 collection 中的所有元素。 

collection作为接口拥有以上这些待实现的方法,除此之外,还有一个default方法和几个为了配合stream的方法,只有在1.8的jdk中可见。接口中已经实现的方法是removeIf,参数为Predicate类的过滤器。

2. Iterator

Iterator<Integer> it = new Iterator<>();
Iterator<Integer> it = queue.iterator();

Iterator类很简单,只有三个方法,next、hasnext、remove。和一个已经被实现的方法forEachRemaining,接受一个Consumer类对象,意思是对剩余未迭代对象进行消费。

注意位置!Iterator的位置在对象和对象之间,起始位置是第一个对象前。这种情况造成了很多限制,不能连续remove、开始不能直接remove。

为什么有这些限制呢?因为Iterator代码实现的时候,设置了两个变量,一个负责记录下一个位置的索引,另一个负责记录刚才走过位置的索引,如果刚才的位置被删除或者刚开始时,第二个参数的值都是-1,不能继续进行remove。下面贴上一些相关代码。

        int cursor = 0;

        int lastRet = -1;

        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size();
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

3. List

List作为直接继承Collection的接口,方法差不多,其中实现了sort方法,怕在List类型下直接被Stream调用sort,这个方法的实现很有必要。

除此之外,

default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

List中实现了replaceAll的方法,这个方法接收一个UnaryOperator接口实例,这个接口就是简化版Function接口,参数和输出要保持一直的意思,这里贴一下UnaryOperator的源代码。

public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

虽然UnaryOperator比较大的卖点在于identity,但是估计List的意思是还是看中了它本身的意思,一元运算符。允许对所有元素做替换。

除此之外,List类中还有ListIterator实例,既然有实例,那就也要有调用的方法。ListIterator<E> listIterator(); ListIterator<E> listIterator(int index);

4. ListIterator

ListIterator继承了Iterator接口,专门为List设计,在原来的方法的基础上增加了向前看,查前/后索引的功能。而且可以进行值的设置。

5. AbstractCollection

从这个方法开始将会慢慢实现上面“挖的坑”,将会逐渐实现部分方法。但是AbstractCollection中实现的基本都是通用方法,类似clear,addAll这类即使具体的数据结构不同也不会有差别的方法。

6. AbstractList

这个类中实现了Itrator的所有方法,具体的数据结构和变量方法就像Iterator中描述的那样。

7. Set

什么都没做,照搬了所有Collection的方法。

8.Queue

Queue不算是数据结构中比较主流的一个结构,因为队列的操作可以被list模仿,但是java还是为Queue提供了一套全新的方法

    boolean add(E e);

    boolean offer(E e);
    
    E remove();
    
    E poll();

    E element();

    E peek();

9. AbstractSet

一共三个实现方法,equals、hashCode、removeAll。

    public int hashCode() {
        int h = 0;
        Iterator<E> i = iterator();
        while (i.hasNext()) {
            E obj = i.next();
            if (obj != null)
                h += obj.hashCode();
        }
        return h;
    }

其中hashcode的实现比较有意思,AbstractSet实现类对象的hashcode值是其中的每个对象的hashcode值加起来之和。

10. SortSet

SortSet是比较关键的一个接口,这个接口提供了为Set排序的概念,TreeSet就是继承这个接口。


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

    Comparator<? super E> comparator();

    SortedSet<E> subSet(E fromElement, E toElement);

    SortedSet<E> headSet(E toElement);

    SortedSet<E> tailSet(E fromElement);

    E first();

    E last();

11. AbstractSequentialList

    public E get(int index) {
        try {
            return listIterator(index).next();
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

    public E set(int index, E element) {
        try {
            ListIterator<E> e = listIterator(index);
            E oldVal = e.next();
            e.set(element);
            return oldVal;
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

    public void add(int index, E element) {
        try {
            listIterator(index).add(element);
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

    public E remove(int index) {
        try {
            ListIterator<E> e = listIterator(index);
            E outCast = e.next();
            e.remove();
            return outCast;
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        try {
            boolean modified = false;
            ListIterator<E> e1 = listIterator(index);
            Iterator<? extends E> e2 = c.iterator();
            while (e2.hasNext()) {
                e1.add(e2.next());
                modified = true;
            }
            return modified;
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

这个类是直接被LinkedList继承的一个抽象类,说实话我并不知道为什么需要这个类,这些方法在LinkedList中又被重写了。java集合类库不是一天写完的,可能在很多个版本更迭中需要这个抽象类,那么,它就这样出现了。

12. Map

以上11种是所有Collection继承下的接口和抽象类,从此以下是所有Map下的接口和抽象类。


public interface Map<K,V> {
  
    int size();
    
    boolean isEmpty();
    
    boolean containsKey(Object key);

    boolean containsValue(Object value);

    V get(Object key);

    V put(K key, V value);

    V remove(Object key);

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

    void clear();

    Set<K> keySet();

    Collection<V> values();

    Set<Map.Entry<K, V>> entrySet();

    interface Entry<K,V> {
   
        K getKey();

        V getValue();

        V setValue(V value);

        boolean equals(Object o);

        int hashCode();

        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }

        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
        }

        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
        }
        
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
        }
    }

    boolean equals(Object o);

    int hashCode();

    default V getOrDefault(Object key, V defaultValue) {
        V v;
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }

    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }

    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }

            // ise thrown from function is not a cme.
            v = function.apply(k, v);

            try {
                entry.setValue(v);
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
        }
    }

13. AbstractMap

和之前的其他被Abstract冠名的类相似,AbstractMap把Map的基本方法都实现了一遍,实际上这些方法还会被具体的HashMap等再实现,但在此类中实现,为其他人继承AbstractMap而创建自己的Map提供了一个方便。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值