java容器的数据结构-ArrayList,LinkList,HashMap

ArrayList:
初始容量为10,底层实现是一个数组,Object[] elementData
自动扩容机制,当添加一个元素时,数组长度超过了elementData.leng,则会按照1.5倍进行扩容
private void grow() {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
contains()方法的实现 ,注意ArrayList中是可以放null对象的
public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
 
public int indexOf(Object o) {
        if (o == null) {              //首先判断对象是否为null,不是的话才可以执行o.equals(elementData[i])
            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;
    }
ArrayList如何转化成数组呢?
 * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * @return an array containing all of the elements in this list in
     *         proper sequence
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
随机获取某个位置的元素
 /**
     * Returns the element at the specified position in this list.
     */
    public E get(int index) {
        rangeCheck(index);
 
        return elementData(index);
    }
 
 @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }
添加一个元素,首先判断是否需要扩容
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
retainAll()方法,取两个集合的交集
/**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     */
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }
遍历整个容器
    /**
     * Returns an iterator over the elements in this list in proper sequence.
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }
 
 private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
 
        public boolean hasNext() {
            return cursor != size;
        }
 
        @SuppressWarnings("unchecked")
        public E next() {
            int i = cursor;
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
    }
 
 
LinkedList:基于链表实现,插入和删除非常高效,只需要改变指针指向的位置,不需要像ArrayList那样整体挪动元素。LinkedList中主要提供了三个基本属性,size,first,last,初始容量size为0,可以简单的把first,last理解为两个指针,分别指向第一个节点和最后一个节点。
/**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)  
     */
    transient Node<E> first;    //first本身也是一个Node,没有previous元素,仅仅是指向队列首元素的标志
 
    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;     //last本身也是一个Node,没有next元素,仅仅是指向队列末尾元素的标志
 
链表中每一个元素都是一个Node(节点)
 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;
        }
    }
 
在链表的某个位置前插入一个新的节点,要让这三个节点的指针互相指向。
/**
     * Inserts element e before non-null Node succ.
     */
    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }
 
让元素成为链表中的第一个元素,该方法只用于研究使用
    /**
     * Links e as first element.
     */
    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);  //创建了一个节点,prev为null,last为原先的第一个元素
        first = newNode;         //让first指针指向第一个元素 newNode
        if (f == null)
            last = newNode;      //如果容器里开始一个元素都没有,则让last也指向新添加的元素newNode
        else                       如果容器里开始就已经有元素了,则first此时已经变为第二个元素
            f.prev = newNode;
        size++;
        modCount++;
    }
获得容器的第一个元素
    /**
     * Returns the first element in this list.
     */
    public E getFirst() {
        final Node<E> f = first;
        if (f == null)       //如果容器里一个元素都没有,则抛出异常,如果有元素,则第一个元素就是first
            throw new NoSuchElementException();
        return f.item;
    }
 
获得容器中的最后一个元素
 /**
     * Returns the last element in this list.
     */
    public E getLast() {
        final Node<E> l = last;
        if (l == null)    ////如果容器里一个元素都没有,则抛出异常,如果有元素,则最后一个元素就是last
            throw new NoSuchElementException();
        return l.item;
    }
 
删掉容器中的第一个元素
/**
     * Unlinks non-null first node f.
     */
    private E unlinkFirst(Node<E> f) {
        final E element = f.item;
        final Node<E> next = f.next;  //获得下一个节点,当删掉第一个节点后,后一个节点就变成第一个节点了
        f.item = null;      //将节点中的item赋值为空
        f.next = null;      // 将指针next赋值为空
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;  
        size--;
        modCount++;
        return element;
    }
 
删掉容器中间的某个元素
 /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  
     */
 public boolean remove(Object o) {
        if (o == null) {         //首先判断删除的Element是否为空
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }
 
 /**
     * Unlinks non-null node x.
     */
    E unlink(Node<E> x) {       该方法至关重要,删除中间节点的操作 
        final E element = x.item;
        final Node<E> next = x.next;       //获得当前结点的下一个节点
        final Node<E> prev = x.prev;       //获得当前结点的上一个节点
 
        if (prev == null) {
            first = next;                  //如果prev是空值的话,则说明当前删的是第一个节点,那么删除后first
        } else {                             指针将指向x的下一个节点next
            prev.next = next;              //如果不是的话,则有左边的指针指向关系
            x.prev = null;       
        }
 
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
 
        x.item = null;                     //总之,要删掉节点x,需要将prev,next,item都赋值为null
        size--;
        modCount++;
        return element;
    }
 
判断是否包含某个元素,元素在哪个具体位置(index)
public boolean contains(Object o) {
        return indexOf(o) != -1;
    }
 /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     */
    public int indexOf(Object o) {
        int index = 0;           //设置一个计数器
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;         //每次循环,如果不是得话就++
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }
 
遍历整个容器,返回ListIterator双向迭代器
 /**
     * The list-iterator is <i>fail-fast</i>: if the list is structurally
     * modified at any time after the Iterator is created, in any way except
     * through the list-iterator's own {@code remove} or {@code add}
     * methods, the list-iterator will throw a
     * {@code ConcurrentModificationException}.  Thus, in the face of
     * concurrent modification, the iterator fails quickly and cleanly, rather
     * than risking arbitrary, non-deterministic behavior at an undetermined
     * time in the future.
     */
    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }
 
fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件(快速失败行为)。
(注意:结构上的修改是指添加或删除一个或多个映射关系的任何操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)
 
 

迭代器指向的位置是元素之前的位置,如下图所示:

    

    

这里假设集合List由四个元素List1、List2、List3和List4组成,当使用语句Iterator it = List.Iterator()时,迭代器it指向的位置是上图中Iterator1指向的位置,当执行语句it.next()之后,迭代器指向的位置后移到上图Iterator2所指向的位置。

Iterator迭代器包含的方法有:

hasNext():如果迭代器指向位置后面还有元素,则返回 true,否则返回false

next():返回集合中Iterator指向位置后面的元素

 

ListIterator迭代器包含的方法有:

hasNext():以正向遍历列表时,如果列表迭代器后面还有元素,则返回 true,否则返回false

hasPrevious():如果以逆向遍历列表,列表迭代器前面还有元素,则返回 true,否则返回false

next():返回列表中ListIterator指向位置后面的元素

previous():返回列表中ListIterator指向位置前面的元素

 
 
HashMap:默认初始化大小为16
 /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 
负载因子为0.75
 /**
     * The load factor used when none specified in constructor.
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
 
当超过length*factor时,HashMap就会自动扩容,按照两倍进行扩容。
 
HashMap底层由数组实现(具体来讲是数据加链表)  Node<K,V>[] table;
 
static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
 
        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }
 
往HashMap中放入一个Mapping
public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);                        //首先获得key的hash值
        int i = indexFor(hash, table.length);        //其次计算出应该放在table的哪个位置(桶)
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {   //桶由链表构成
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
                V oldValue = e.value;
                e.value = value;                //如果要插入的Mapping的Hash值和key与桶中的某个
                e.recordAccess(this);             Mapping完全相同,则替换掉它的value值
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }
 
final int hash(Object k) {
        int h = 0;
        h ^= k.hashCode();

        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
static int indexFor(int h, int length) {
        return h & (length-1);
    }

当需要插入的keynull时,调用putForNullKey方法处理:

 
 private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }
 
   当需要插入的keynull时,调用putForNullKey方法处理:
 
 private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;    //如果HashMap中有<null,value>这样的Node,则一定是放在table的
                e.value = value;           首位置,因为null的hash值为0
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null; 
    }
添加一个Entry,首先判断是否需要扩容,size表示table(数组)当前的元素个数,扩容时按照两倍的方式扩容,之后还需要重哈希(rehash)
 void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }
真正意义上的添加Entry,首先获得链表原来的头节点e,然后构造一个新的节点,使其next指针指向e:
void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }
 
 
在HashMap中如何根据key获得相应的value值呢?
public V get(Object key) {
        if (key == null)           //首先判断key是否为null
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }
 
private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }
 
final Entry<K,V> getEntry(Object key) {
        int hash = (key == null) ? 0 : hash(key);  //首先获得key的hash值
        for (Entry<K,V> e = table[indexFor(hash, table.length)];//获得key在table中的index
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&         //如果完全相同,则返回key对应的Entry
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

 

posted @ 2017-06-12 23:58  bili111  阅读(225)  评论(0编辑  收藏  举报