ArrayList:

1. ArrayList是List接口的大小可变数组的实现,此实现是不同步的。

2. ArrayList内部使用类型为Object[]的数组存储元素。

3. ArrayList默认的数组长度为10, 当需要扩大容量时,扩大后的容量为:newCapacity = (oldCapacity * 3)/2 + 1;

4. ArrayList的clone方法为浅拷贝(shallow copy)

5. ArrayList的remove方法根据参数类型的不同有两种重载:

remove(int index) : 删除指定位置的元素;

remove(Object o)  : 删除第一个遇到的元素,如果没有不做改变

6. ArrayList允许null值、允许重复值、不排序,获取快速,增删麻烦。

HashMap:

HashMap是不同步的。

 HashMap内部使用类型为Entry[]的数组存储元素。Entry是HashMap的一个内部类,定义如下所示。

 每一个Entry对象其实是一个单向链表,之后的解析可以看到,最后存入的元素在最前面。

备注:下面出现的代码都是HashMap.java中的源码,中文描述是作者加的。

 transient Entry[] table;//HashMap内部定义的数据存储变量
     //内部类
     static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        final int hash;
        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }

       *****
       省略
       *****
    }

HashMap中几个概念:

capacity:容量,即Entry[]数组的长度

 loadFactor:负载因子,Entry[]数组中实际数据量/容量的比例达到loadFactor时,HashMap就需要扩大容量了,一般扩大为原来的两倍。

 threshold: 当HashMap中的元素个数超过这个数值时,就将扩大容量。

put方法:

public V put(K key, V value) {
        if (key == null)
        //如果key为null,特殊处理,key为null直接存储在table[0]位置。
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);//此处得到的i即为key对应的HashMap中的存储位置table[i]
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        //从Entry链表的第一个开始如果找到与key执行equals方法为true的Entry,则修改对应Entry的value值为新值,key不做修改
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        //如果没有找到对应的key,则执行增加操作
        addEntry(hash, key, value, i);
        return null;
    } 

void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            //如果大小超过了threshold,扩大容量为原来的两倍。扩大容量时,所有的key-value需要重新hash。
            resize(2 * table.length);
}

void resize(int newCapacity) {
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return;
    }
    Entry[] newTable = new Entry[newCapacity];
    transfer(newTable);//将原来hash表中的数据放入新的hash表中,需要重新hash。
    table = newTable;
    threshold = (int)(newCapacity * loadFactor);
}

/**
 * Transfers all entries from current table to newTable.
 */
void transfer(Entry[] newTable) {
    Entry[] src = table;
    int newCapacity = newTable.length;
    for (int j = 0; j < src.length; j++) {
        Entry<K,V> e = src[j];
        if (e != null) {
            src[j] = null;
            //此处使用循环,将原来hash链中的所有的key-value都重新获取hash值,重新放置。
            //因为放置位置是跟hash表的大小有关的,当hash表容量扩大后,之前放在一个地方的key-value对现在可能hash不到同一个地方了。
            do {
                Entry<K,V> next = e.next;//记录此处的下一个地址
                int i = indexFor(e.hash, newCapacity);//重新计算当前的key-value在新hash表中的位置
                e.next = newTable[i];//将之前在同一位置的数据放在e的next位置,没有则为null
                newTable[i] = e;//将e作为hash表i位置的第一个元素
                e = next;//将next赋值给e, 对原来j位置的所有的元素都执行重新hash,重新放置
            } while (e != null);
        }
    }
}

get方法:按照put时的逻辑根据key获取value。不再详述。

keySet与values方法:

这两个方法作用好理解,但需要注意的是,当对keySet()和values()方法获取到的集合执行remove操作的时候就相当于对HashMap集合本身执行remove操作。看源码通过keySet和values获取到的好像是HashMap的迭代器,这里我没有深究。如果谁明白具体原因不吝赐教。

HashSet:

HashSet的内部是用的HashMap实现的,使用Entry将每一个HashSet元素的引用存储在key位置,value位置使用默认的数据填充。

 在此也可以看到,HashMap中的key-value对其实可以看成value是每一个key的附属,只需要找到每一个key的位置,然后把对应的value放入即可。

ArrayList、HashMap、HashSet源码总结的更多相关文章

  1. HashSet源码学习,基于HashMap实现

    HashSet源码学习 一).Set集合的主要使用类 1). HashSet 基于对HashMap的封装 2). LinkedHashSet 基于对LinkedHashSet的封装 3). TreeS ...

  2. 【Java集合】HashSet源码解析以及HashSet与HashMap的区别

    HashSet 前言 HashSet是一个不可重复且元素无序的集合.内部使用HashMap实现. 我们可以从HashSet源码的类注释中获取到如下信息: 底层基于HashMap实现,所以迭代过程中不能 ...

  3. Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  4. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  5. HashSet源码分析

    在java集合中有一种集合Set(集),他有两个实现类,分别是HashSet,TreeSet.下面仔细分析HashSet源码. 看了HashSet的源码就会发现HashSet的底层实现是利用HashM ...

  6. HashSet源码

    public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java. ...

  7. 死磕Java之聊聊HashSet源码(基于JDK1.8)

    HashSet的UML图 HashSet的成员变量及其含义 public class HashSet<E> extends AbstractSet<E> implements ...

  8. HashSet源码分析:JDK源码系列

    1.简介 继续分析源码,上一篇文章把HashMap的分析完毕.本文开始分析HashSet简单的介绍一下. HashSet是一个无重复元素集合,内部使用HashMap实现,所以HashMap的特征耶继承 ...

  9. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例

    概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...

  10. 【转】Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例

    原文网址:http://www.cnblogs.com/skywang12345/p/3308556.html 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具 ...

随机推荐

  1. [Codeforces 961G]Partitions

    Description 题库链接 给你 \(n\) 个不同的元素组成的集合 \(R\) ,每个元素有一个权值 \(w\) .对于一个子集集合 \(S\) ,它的价值为 \(W(S)=|S|\cdot\ ...

  2. UVA 3485 Bridge

    题目大意 你的任务是修建一座大桥.桥上等距地摆放着若干个塔,塔高为H,宽度忽略不计.相邻两座塔之间的距离不能超过D.塔之间的绳索形成全等的对称抛物线.桥长度为B,绳索总长为L,如下图所示求建最少的塔时 ...

  3. hdu 5877 线段树(2016 ACM/ICPC Asia Regional Dalian Online)

    Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total ...

  4. hdu 4670 Cube number on a tree(点分治)

    Cube number on a tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/ ...

  5. 浅析Linux内核调度

    1.调度器的概述 多任务操作系统分为非抢占式多任务和抢占式多任务.与大多数现代操作系统一样,Linux采用的是抢占式多任务模式.这表示对CPU的占用时间由操作系统决定的,具体为操作系统中的调度器.调度 ...

  6. # C语言程序设计第一次作业1234

    ---恢复内容开始--- C语言程序设计第一次作业 1.求圆面积和周长 输入圆的半径,计算圆的周长和面积 (1)流程图 (2)测试数据及运行结果 测试数据r=3 运行结果 2.判断闰年 输入一个四位年 ...

  7. Springboot整合log4j2【详细步骤】

    1.去除logback中的依赖包 <dependency> <groupId>org.springframework.boot</groupId> <arti ...

  8. 【精解】EOS智能合约演练

    EOS,智能合约,abi,wasm,cleos,eosiocpp,开发调试,钱包,账户,签名权限 热身 本文旨在针对EOS智能合约进行一个完整的实操演练,过程中深入熟悉掌握整个EOS智能合约的流程,过 ...

  9. CentOS7.2安装jdk7u80

    1.cd /usr/local 2.tar zxvf jdk-7u80-linux-x64.tar.gz 3.vi /etc/profile 4.输入i 加入内容如下: export JAVA_HOM ...

  10. LintCode题解之判断是否为平方数之和

    简单粗暴 public class Solution { /* * @param : the given number * @return: whether whether there're two ...