集合

集合

  • 集合实际上就是一个容器,是一个载体,可以用来容纳其他数据

  • 集合不能存基本数据,存储的都是引用,集合本身就是一个对象

  • 每一个不同的集合,对应了不同的数据结构,不同的数据结构存储数据的方式不同

    ​ 数组、链表、二叉树、哈希表....

  • 都在java.util.*中

继承结构


Collection一些方法源码分析(ArrayList实现为例)

  1. contains(Object o)

    transient Object[] elementData;
    public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }
    public int indexOf(Object o) {
            if (o == null) {//可以有空值
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))//会调用equals方法
                        return i;
            }
            return -1;
        }
    
  2. remove(Object o)

    public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {//也是调用equals
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
    private void fastRemove(int index) {
         modCount++;
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,numMoved);//全部元素向前移动
            elementData[--size] = null; // clear to let GC do its work
        }
    

集合List接口特有方法(有序可重复,从0开始)

  1. public void add(int index, E element)

    public void add(int index, E element) { //下标从0开始,效率低,用的不多
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1, size - index);
            elementData[index] = element;
            size++;
        }
    
  2. public E get(int index) {
            rangeCheck(index);
            return elementData(index);
        }
    
  3. public E set(int index, E element) {
            rangeCheck(index);
    
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }
    
  4. public E remove(int index) {
            rangeCheck(index);
    
            modCount++;
            E oldValue = elementData(index);
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index, numMoved);
            elementData[--size] = null; // clear to let GC do its work
    
            return oldValue;
        }
    
  5. public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
    ///也有对应的lastIndexOf(Object o)
    

ArrayList初始化及扩容(检索效率高,末尾增删高,随机增删效率低,无法存储大数据量,用的最多)

  1. transient Object[] elementData;
    private int size; //当前元素的个数
    private static final int DEFAULT_CAPACITY = 10;//默认容量是10
    
    public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
            }
        }
    
    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
  2. 扩容,原容量加上原容量右移一位(除以2),相当于1.5倍

    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity; //不一定1.5倍,看minCapcity大小,可能比1.5倍大
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    // Arrays的copyOf方法
    public static <T> T[] copyOf(T[] original, int newLength) {
            return (T[]) copyOf(original, newLength, original.getClass());
        }
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
            @SuppressWarnings("unchecked")
            T[] copy = ((Object)newType == (Object)Object[].class)
                ? (T[]) new Object[newLength]
                : (T[])Array.newInstance(newType.getComponentType(), 
            newLength);
            System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
            return copy;
        }
    
    
  3. 利用集合的构造方法

    public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            if ((size = elementData.length) != 0) {
                // c.toArray might (incorrectly) not return //Object[] (see 6260652)
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            	} else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }
    
    

LinkedList的源码分析

  1. 节点

    private static class Node<E> {
            E item;
            Node<E> next;
            Node<E> prev;
    
            Node(Node<E> prev, E element, Node<E> next) {
                this.item = element;
                this.next = next;
                this.prev = prev;
            }
        }
    
    
  2. 属性

    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;
    
    
  3. public boolean add(E e) {
            linkLast(e);
            return true;
        }
    //很多调用的都是linkLast这个方法
        void linkLast(E e) {
            final Node<E> l = last; //是null
            final Node<E> newNode = new Node<>(l, e, null);//l是上一个节点
            last = newNode;//再让last指向最后的节点
            if (l == null)// 如果是第一个值
                first = newNode;// first也指向该节点
            else
                l.next = newNode;// 双向链表还需要把先前最后节点的next指向它
            size++; //长度加一
            modCount++; //用于遍历时的计数
        }
    
    
  4. //删除主要调用的
    private E unlinkLast(Node<E> l) {
            // assert l == last && l != null;
            final E element = l.item;
            final Node<E> prev = l.prev;
            l.item = null;
            l.prev = null; // help GC
            last = prev;  // last前移
            if (prev == null) // 没节点了
                first = null;
            else
                prev.next = null;
            size--;
            modCount++;
            return element;
        }
    
    
  5. push、pop底层调用的就是removeFirst()、addFirst()

  6. 常用API

    • add(E e): 指定元素追加到列表末尾
    • addFirst(E e)
    • addLast(E e)
    • offer(E e):添加到尾部 调用addsss
    • element():返回头但不删除 调用getFirst() 为null则抛异常
    • peek():返回头但不删除 为null返回null
    • poll():返回并且删除头 为null返回null
    • pop():栈中弹出一个元素 调用removeFirst() 为null则抛异常
    • push(E e):压栈 调用addFirst()
    • removeFirst() 为null则抛异常
    • removeLast() 为null则抛异常
    • getFirst() 为null则抛异常
    • getLast() 为null则抛异常
    • size():返回大小

Vector

  • 底层数组、初始容量为10、扩容为两倍、加synchronized保证线程安全
posted @ 2020-11-07 17:04  星银  阅读(51)  评论(0)    收藏  举报