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;
}

 

java容器的数据结构-ArrayList,LinkList,HashMap的更多相关文章

  1. Java 容器 & 泛型:五、HashMap 和 TreeMap的自白

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Java 容器的文章这次应该是最后一篇了:Java 容器 系列. 今天泥瓦匠聊下 Maps. 一.Ma ...

  2. 理解java容器底层原理--手动实现HashMap

    HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...

  3. Java 容器源码分析之HashMap多线程并发问题分析

    并发问题的症状 多线程put后可能导致get死循环 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问题,所以需要变成多 ...

  4. Java中常见数据结构Map之HashMap

    之前很早就在博客中写过HashMap的一些东西: 彻底搞懂HashMap,HashTableConcurrentHashMap关联: http://www.cnblogs.com/wang-meng/ ...

  5. Java容器深入浅出之Map、HashMap、Hashtable及其它实现类

    在Java中,Set的底层事实上是基于Map实现的,Map内部封装了一个Entry内部接口,由实现类来封装key-value对,当value值均为null时,key的集合就形成了Set.因此,Map集 ...

  6. Java容器学习之ArrayList

    一.概述 ArrayList是java中十分常用的集合类,继承于AbstractList,并实现了List.RandomAccess.Cloneable和Serializable接口.ArrayLis ...

  7. Java容器集合类的区别用法

    Set,List,Map,Vector,ArrayList的区别 JAVA的容器---List,Map,Set Collection ├List │├LinkedList │├ArrayList │└ ...

  8. Java 容器相关知识全面总结

    Java实用类库提供了一套相当完整的容器来帮助我们解决很多具体问题.因为我本身是一名Android开发者,包括我在内很多安卓开发,最拿手的就是ListView(RecycleView)+BaseAda ...

  9. Java中List,ArrayList、Vector,map,HashTable,HashMap区别用法

    Java中List,ArrayList.Vector,map,HashTable,HashMap区别用法 标签: vectorhashmaplistjavaiteratorinteger ArrayL ...

随机推荐

  1. OpenSSL学习笔记

    SSL缺省只进行server端的认证,客户端的认证是可选的.以下是其流程图(摘自TLS协议). 加密算法介绍: 对称加密: DES:date encrption standard,56bit 3DES ...

  2. 基于java 的websocket的聊天功能,一开始初始化websocket,执行打开连接之后就直接关闭连接了。

    1 错误描述: java 后台没有报错,但是就是连接不上,一连上又自动关闭. 2 错误根源: 缺少jar包. 对比了报错的tomcat 的jar包和不报错的jar包 发现是tomcat下缺少上图绿色框 ...

  3. 【BZOJ4636】蒟蒻的数列 STL

    [BZOJ4636]蒟蒻的数列 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个 ...

  4. 目前最火的php框架

    1.yii 作者:宗霖链接:https://www.zhihu.com/question/25023032/answer/75085250来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...

  5. greenplum-cc-web4.0监控安装

    简介: 本文是基于greenplum5.7,greenplum-cc-web4.0安装的. 一.安装greenplum监控的数据库以及创建用户(在gpadmin用户下安装) 1.开启greenplum ...

  6. scrapy - grab english name

    wxpath定位-采集验证-入库-使用. from scrapy.spider import Spider from scrapy.crawler import CrawlerProcess clas ...

  7. xpath-grab english name

    from scrapy.spider import Spider from scrapy.crawler import CrawlerProcess import pymysql conn = pym ...

  8. Apache Kafka源码分析 – Log Management

    LogManager LogManager会管理broker上所有的logs(在一个log目录下),一个topic的一个partition对应于一个log(一个log子目录)首先loadLogs会加载 ...

  9. POJ1330Nearest Common Ancestors最近公共祖先LCA问题

    用的离线算法Tarjan 该算法的详细解释请戳 http://www.cnblogs.com/Findxiaoxun/p/3428516.html 做这个题的时候,直接把1470的代码copy过来,改 ...

  10. 关于Android项目隐藏标题栏的方法总结

    1.在代码中添加这么一行代码 this.requestWindowFeature(Window.FEATURE_NO_TITLE); 注意:这段代码需要写在setContentView()之前,否则会 ...