博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java集合(ArrayList、vector、HashMap、HashTable)源码剖析
阅读量:4079 次
发布时间:2019-05-25

本文共 4284 字,大约阅读时间需要 14 分钟。

记得很久之前有个朋友说他去面试时面试官问他,ArrayList、vector、HashMap、HashTable初始化不指定容量大小时,默认大小是多少,这四者的两两区别,于是后来便找出了jdk源码,看了看,当时告诉结果给朋友后由于忙一直没有写下来,现在趁着有时间写下来记录记录。

首先先说ArrayList。ArrayList这个对象我一共看几个版本JDK,看到两类,第一类就是在初始化时直接指定默认容量,代码如下:

private transient Object[] elementData;public ArrayList(int initialCapacity) {    super();    if (initialCapacity < 0)        throw new IllegalArgumentException("Illegal Capacity: "+                                           initialCapacity);    this.elementData = new Object[initialCapacity];}public ArrayList() {    this(10);}
从代码中可以看出,ArrayList底层其实就是一个Object数组,类包含两个构造器,默认不指定初始容量时会通过this(10)来调用有参构造,初始化一个容量为10的数组。说到这个,肯定就会涉及到超过10个时会怎样处理呢?看如下代码:

private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = elementData.length;//获取当前数组长度        int newCapacity = oldCapacity + (oldCapacity >> 1);//新长度为原长度1.5倍        if (newCapacity - minCapacity < 0)//新长度还是小于所需长度,则数组长度扩展为所需长度            newCapacity = minCapacity;        if (newCapacity - MAX_ARRAY_SIZE > 0)//新长度大于数组最大容量(最大容量Integer.MAX_VALUE - 8,源代码中有体现)时调用下面一个方法,直接取最大值            newCapacity = hugeCapacity(minCapacity);        // minCapacity is usually close to size, so this is a win:        elementData = Arrays.copyOf(elementData, newCapacity);//扩容    }
private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError();        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }
这段代码是在数组容量不足时会触发,参数minCapacity即当前所需容量,我写的注释已经很详细了,其中涉及到>>右移位运算符,右移原理不多讲,右移一位相当于原数值除以2并省掉余数,加上原来的,故为1.5倍。

另看到过一版JDK中ArrayList的无参构造器中直接给数组赋了一个空数组,即初始化时容量为0,当第一次调用add()方法时,会触发grow方法,因暂时没有那版JDK,只能靠记忆简述,后续再补上,那个版本定义了一个常量,值为10,在扩容时会有一个分支,如果初始为空数组,则会扩容成常量值长度(即为10)的容量,以此来达到一种懒汉模式的效果。

然后是Vector,vector底层原理其实跟ArrayList一样,只是很多方法中加入了锁,故Vector是线程安全的,当然,效率会低于ArrayList,初始化代码如下:

public Vector(int initialCapacity, int capacityIncrement) {    super();    if (initialCapacity < 0)        throw new IllegalArgumentException("Illegal Capacity: "+                                           initialCapacity);    this.elementData = new Object[initialCapacity];    this.capacityIncrement = capacityIncrement;}public Vector(int initialCapacity) {    this(initialCapacity, 0);}public Vector() {    this(10);}
这里可以看到,Vector比ArrayList多了一个两个参数的构造器,但是初始化长度依旧为10,那么那个两个参数的构造器中后一个参数
capacityIncrement是什么呢?看如下代码:

private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + ((capacityIncrement > 0) ?                                 capacityIncrement : oldCapacity);//此处用到capacityIncrementif (newCapacity - minCapacity < 0)    newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)    newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflow    throw new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?    Integer.MAX_VALUE :    MAX_ARRAY_SIZE;}
代码中注释的部分可以看出,如果初始化
capacityIncrement>0,则Vector扩容时增量为capacityIncrement,即我们构造器的第二个参数,如果不指定,默认为0,则增量为原大小。
接下来就是HashMap,由于本文重点讨论初始化大小,则只关注初始化,其他细节会另写文章做说明,初始化代码如下:

static final int DEFAULT_INITIAL_CAPACITY = 16;public HashMap() {    this.loadFactor = DEFAULT_LOAD_FACTOR;    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);    table = new Entry[DEFAULT_INITIAL_CAPACITY];    init();}
代码中可以看到,定义了一个常量为16,无参构造是会通过table = new Entry[DEFAULT_INITIAL_CAPACITY];来初始化一个长度为16的元素为链表结构的数组。

最后是HashTable,HashTable也是加入了很多锁,故也是线程安全的,同样会降低效率,代码如下:

public Hashtable(int initialCapacity, float loadFactor) {    if (initialCapacity < 0)        throw new IllegalArgumentException("Illegal Capacity: "+                                           initialCapacity);    if (loadFactor <= 0 || Float.isNaN(loadFactor))        throw new IllegalArgumentException("Illegal Load: "+loadFactor);    if (initialCapacity==0)        initialCapacity = 1;    this.loadFactor = loadFactor;    table = new Entry[initialCapacity];    threshold = (int)(initialCapacity * loadFactor);}public Hashtable(int initialCapacity) {    this(initialCapacity, 0.75f);}public Hashtable() {    this(11, 0.75f);}
通过代码可以看到,同样有三个构造器,无参默认初始化长度为11。

今天的内容到此为止,另一版的ArrayList我会找时间补上,大家有什么异议可以提出,互勉才能进步嘛。

转载地址:http://wesni.baihongyu.com/

你可能感兴趣的文章
PostgreSQL代码分析,查询优化部分,pull_ands()和pull_ors()
查看>>
IA32时钟周期的一些内容
查看>>
获得github工程中的一个文件夹的方法
查看>>
《PostgreSQL技术内幕:查询优化深度探索》养成记
查看>>
PostgreSQL查询优化器详解之逻辑优化篇
查看>>
STM32中assert_param的使用
查看>>
C语言中的 (void*)0 与 (void)0
查看>>
vu 是什么
查看>>
io口的作用
查看>>
IO口的作用
查看>>
UIView的使用setNeedsDisplay
查看>>
归档与解归档
查看>>
Window
查看>>
为什么button在设置标题时要用一个方法,而不像lable一样直接用一个属性
查看>>
字符串的截取
查看>>
2. Add Two Numbers
查看>>
17. Letter Combinations of a Phone Number (DFS, String)
查看>>
93. Restore IP Addresses (DFS, String)
查看>>
19. Remove Nth Node From End of List (双指针)
查看>>
49. Group Anagrams (String, Map)
查看>>