JAVA中对集合源码的理解

一、常见的数据结构

1.数据结构的概念

  • 数据结构,就是一种程序设计优化的方法论,研究数据的“逻辑结构、和物理结构以及它们之间相互关系并对这种结构定义相应的、运算,目的是加快程序的执行速度、诚少内存占用的空间。

2.数据结构的研究对象

  • 研究对象1:数据之间的逻辑关系

集合结构
线性结构:一对一关系
树形结构:一对多关系
图形结构:多对多关系

  • 研究对象2:数据的存储结构(或物理结构)

顺序结构
链式结构
索引结构
散列结构

开发中,更习惯如下的方式理解存储结构
线性表(一对一关系):一维数组、单向链表、双向链表、栈、队列
树(一对多关系):各种树
图(多对多关系)
哈希表

  • 研究对象3:

分配资源,建立结构、释放资源
插入和删除
获取和遍历
修改和排序

二、List实现类源码分析

1.ArrayList

  • ArrayList的特点

实现了List接口,存储有序的、可以重复的数据
底层使用Object[]数组存储
线程不安全的

  • ArrayList源码分析:

JDK7版本:

//如下代码的执行:底层会初始化数组,数组的长度为10. Object[] elementData = new Object[10];
ArrayList list = new ArrayList<>();
list.add(“aa”); //elementData[0] = “aa”;
list.add(“bb”); //elementData[0] = “bb”;

当要添加第11个元素的时候,底层的elementData数组已满,则需要扩容。默认扩容为原来长度的1.5倍。并将原有数组中的元素复制到新的数组中。

JDK8版本

//如下代码的执行:底层会初始化数组,即: Object[] elementData = new Object[]{ };
ArrayList list = new ArrayList<>();
list.add(“aa”); //首次添加元素时,会初始化数组elementData = new Object[10];elementData[0] = “aa”
list.add(“bb”); //elementData[0] = “bb”;

当要添加第11个元素的时候,底层的elementData数组已满,则需要扩容。默认扩容为原来长度的1.5倍。并将原有数组中的元素复制到新的数组中。

  • 小结:

jdk1.7中:ArrayList类似于饿汉式
jdk1.8中:ArrayList类似于懒汉式

2.vector

  • vector的特点:

实现了List接口,存储有序的、可以重复的数据
底层使用Object[]数组存储
线程安全的

  • vector源码分析(以jdk1.8为例):

Vector v = new Vector(); //底层初始化数组,长度为10;Object[] elementData = new Object[10];
v.add(“AA”); //elementData[0] = “AA”;
v.add(“BB”); //elementData[0] = “BB”;

当添加第11个元素时,需要扩容。默认扩容为原来的2倍。

3.LinkedList

  • LinkedList的特点:

实现了List接口,存储有序的、可以重复的数据
底层使用双向链存储
线程不安全的

  • LinkedList在jdk8中的源码解析:

LinkedList< String> list = new LinkedList<>(); //底层没干啥
list.add(“aa”); //将"aa"封装到一个Node对象1中,list对象的属性first、last都指向此Node对象1

list.add(“bb”); //将"bb"封装到一个Node对象2中,对象1和对象2构成一个双向链表,同时 last指向此Node对象2

因为LinkedList内部使用的是双向链表,不需要考虑扩容问题
LinkedList内部声明:
private static class Node< E>{
E item;
Node< E> next;
Node< E> prev;
}

4.启示与开发建议

Vector基本就不用了
ArrayList底层使用数组结构,查找和添加操作效率高,时间复杂度为O(1),删除和插入操作效率低,时间复杂度为O(n)
LinkedList底层使用双向链表结构,删除和插入操作效率高,时间复杂度为O(1),查找和添加操作效率低,时间复杂度为O(n),有可能添加操作是O(1);
在选择了ArrayList的前提下,new ArrayList():底层创建长度为10的数组。new ArrayList():底层创建长度为10的数组。new ArrayList(int capacity):底层创建指定capacity长度的数组。
如果在开发中,大体确定数组的长度,推荐使用带参的构造器,避免了多次底层扩容、复制数组。

三、Map实现类源码分析:

1.HashMap

  • HashMap中元素的特点:

HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key就构成一个Set集合。—>key所在的类要重写HashCode()和equals()方法
HashMap中的所有的value彼此之间是重复的、无序的。所有的value就构成一个Collection集合。—>value所在的类要重写equals()方法
HashMap中的一个key-value,就构成了一个entry
HashMap中所有的entry彼此之间是不可重复的、无序的。所有的entry就构成了一个Set集合

  • HashMap源码分析:

jdk7中创建对象和添加数据过程:

//创建对象的过程中,底层会初始化数组Entry[] table = new Rntry[16];
HashMap< String , Interger> map = new HashMap<>();

map.put(“AA” , 78);//"AA"和78封装到一个Entry对象中,考虑将此对象添加到table数组中。

添加/修改的过程:
将(key1 , value1)添加到当前的map中:
首先,需要调用key1所在类的hashCode()方法,计算key1对应的哈希值1,此哈希值1经过某种算法(hash())之后,得到哈希值2.哈希值2再经过某种算法(indexFor())之后,就确定了(key1 , value1)在数组table中的索引位置i.此时会出现如下情况:
情况1:此索引位置i上没有元素,则(key1 , value1)添加成功。
如果此索引位置i上有元素(key2 , value2),则需要继续比较key1和和key2的哈希值2(哈希冲突)
情况2:如果key1的哈希值2与key2的哈希值2不同,则(key1 , value1)添加成功。
如果key1的哈希值2与key2的哈希值2相同,则需要继续比较key1和key2的equals()。要调用key1所在类的equals(),将key2作为参数传递进去。
情况3:调用equals(),返回false:则(key1,value1)添加成功。
调用equals(),返回true:则认为key1和key2是相同的。默认情况下,value1替换原有的value2。

说明:

情况1:将(key1,value1)存放到数组的索引i的位置
情况2;情况3:(key1 , value1)元素与现有的(key2 , value2)构成单向链表结构,(key1,value1)指向(key2,value2)

jdk8和jdk7的不同之处

在jdk8中,当我们创建了HashMap实例以后,底层并没有初始化table数组。当首次添加(key , value)时,进行判断,如果发现table尚未初始化,则对数组进行初始化。
在jdk8中,HashMap底层定义了Node内部类,替换jdk7中的Entry内部类。意味着,我们创建的数组是Node[]
在jdk8中,如果当前的(key , value)经过一系列判断之后,可以添加到当前的数组下标i中,如果此时下标位置上有元素。在jdk7中是将新的(key , value)指向已有的旧元素(头插法),而在jdk8中国是旧的元素指向新的(key , value)元素(尾插法):七上八下“”
jdk7:数组 + 单向链表
jdk8:数组 + 单向链表 + 红黑树
什么时候会使用单向链表变为红黑树:如果数组索引i位置上元素的个数达到8,并且数组的长度达到64时,我们就将此索引i位置上的多个元素改为使用红黑树的结构就行存储。因为红黑树增删查的效率高
什么时候会使用红黑树转变为单向链表:当使用红黑树的索引i位置上的元素的个数低于6的时候,就会将红黑树结构退化为单向链表。

2.LinkedHashMap

  • LinkedHashMap与HashMap的关系

LinkedHashMap是HashMap的子类。
LinkedHashMap在HashMap使用的数组+单向链表+红黑树的基础上,又增加了一对双向链表,记录添加的(key , value)的先后顺序。便于我们遍历所有的key - value.
LinkedHashMap重写了HashMap的如下方法:
newNode();
LinkedHashMap内部定义了一个继承于Node的Entry

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爪哇哇哇哇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值