list map set 在项目中的应用,阐述底层实现原理

简单的介绍一下:

List , Set, Map都是接口,前两个继承至Collection接口,Map为独立接口
Set下有HashSet,LinkedHashSet,TreeSet
List下有ArrayList,Vector,LinkedList
Map下有Hashtable,LinkedHashMap,HashMap,TreeMap
Collection接口下还有个Queue接口,有PriorityQueue类
Queue接口与List、Set同一级别,都是继承了Collection接口。

LinkedList既可以实现Queue接口,也可以实现List接口.只不过呢, LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用

SortedSet是个接口,它里面的(只有TreeSet这一个实现可用)中的元素一定是有序的。

Connection接口:
— List 有序,可重复

ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高
Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低
LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高


—Set 无序,唯一

HashSet
底层数据结构是哈希表。(无序,唯一)
如何来保证元素唯一性?
1.依赖两个方法:hashCode()和equals()

LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一

TreeSet
底层数据结构是红黑树。(唯一,有序)
1. 如何保证元素排序的呢?
自然排序
比较器排序
2.如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定


项目实用:

在整个项目当中List是使用最多的

例如

 List<Classes>  getListClasses();

使用List接收集合对象

map也有所使用例如:

 Map<String,List<UniversityUser>> map = new HashMap<String,List<UniversityUser>>();
        map.put("success",userEntityList);
        map.put("error",errorEntityList);

        return map;

为了接收多个不同的List对象

实现原理介绍

一、list底层原理

首先list下有ArrayList、LinkedList、Vector三个实现类。

ArrayList的底层原理:

1.ArrayList的底层原理是由动态数组实现的。其数组的长度是随着元素的增多而变长的;当实例化ArrayList时(List array = new ArrayList();)它的长度是默认为10。
2.ArrayList是有顺序的,当ArrayList增添元素时,他是按照顺序从头部往后添加的。
3.当新增的数据超过当前数组时,它会创建一个新的数组,其新数组的长度为当前数组的1.5倍,然后将当前数组的元素复制到新数组中,当前数组的内存被释放。
4.数组存在的位置为在JVM的堆中,用来存储固定大小同类型元素的。当新的元素需要存储时,会存储在最前面,所以每次存储新元素时,所有的元素都会向后移动位置。同理,删除一个元素时,数组中所有的元素都会向前移动位置,所以ArrayList对于增删的效率很低。
5.数组里面的元素占用的内存相同并且连续排列的。在查询时可以根据数组的下标来进行快速访问,所以ArrayList对于查询效率高。
 

LinkedList的底层原理:

LinkedList底层是由双向链表来实现的。
1.双向链表是由三部分来组成的:prev、data、next

prev:存储上一个节点的地址;
data:存储将要存储的数据;
next:存储下一个节点的地址;
2.双向链表的排序方式是没有顺序的;当我们新增一个元素时,只需要修改前一个元素的next和后一个元素的prev即可,删除元素同理;这样使得LinkedList对于新增和删除的效率大大提高。但是查询数据时,需要一个一个的查找,直到找到为止,使得查询的效率变得很低。
 

Vector的底层原理:

Vector实现类可以完全支持List的全部功能的。Vector和ArrayList相似,也是有数组实现,默认为10;相对于ArrayList来说,虽然说Vector是线程安全的,但是在性能方面不如ArrayList;
1.在JDK1.0中继承类和实现接口。

2.Vector中的基本属性
protected Object[] elementData;//存放元素的数组
protected int elementCount;//数组中存放的个数
protected int capacityIncrement;//数组的增长系数

3.对于使用来说ArrayList比Vector使用效率会更高,因为在Vector的源码中每个方法中都添加了一个为synchronized的关键字来保证同步,虽然保证了线程的安全,但是在使用效率上大大降低。
 

4.同样在查找给定元素索引值等的方法中,源码都将该元素的值分为null和不为null两种情况处理,Vector中也允许元素为null。

二、map底层原理

一、HashMap底层实现原理(重点)

在jdk7中:

当执行方法 put(key1,value1) 添加数据时,HashMap底层的实现原理如下(此前可能已经执行过多次put()方法):

首先,调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过底层算法的计算以后,可以得到在Entry数组中的存放位置,接下来又分为三种情况。

情况1:如果此位置上的数据为空,此时的key1-value1添加成功。

情况2:如果此位置上数据不为空(意味着此位置上存在一个或多个数据(多个数据以链表的形式存在)),则比较key1和已经存在的数据的哈希值,如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功,即key1-value1和原来的数据会以链表的形式存储。

情况3:与情况二类似,在比较key1和已经存在的数据的哈希值时,如果key1的哈希值和某个已经存在的数据(如key2-value2)的哈希值相同,则调用key1所在类的equals()方法,返回key1和key2的比较结果,如果返回的是false,此时key1-value1添加成功,同样也是和原来的数据以链表的形式存储;如果返回的是true,则会使用value1替换value2。

在不断添加数据的过程中,会涉及到数组的扩容问题。当添加数据超出临界值(且数据要存放的位置非空)时,需要对数组扩容。默认的扩容方式:扩容为原来容量的2倍,并将原来的数据复制过来。
 

在jdk8中:

(1). 使用空参构造器创建HashMap对象时,底层没有直接创建一个长度为16的数组。
(2). jdk8底层存储数据的数组使用的是Node[ ],而不是Entry[ ] 。
(3). jdk8在首次调用put()方法时,底层才会创建长度为16的数组。
(4). jdk7中底层存储数据的结构是:数组+链表。jdk8中底层存储数据的结构是:数组+链表+红黑树。
(5).当存储数据形成链表时,链表的结构不相同,jdk7的链表结构是:新的数据指向旧的数据。jdk8的链表结构是:旧的数据指向新的数据。
(6).当底层数组的某一个索引位置上的元素以链表形式存在的数据个数大于8 ,且当前数组的长度大于64时,此时这个索引位置上的数据改为使用红黑树存储。
 

HashMap底层重要属性的说明
DEFAULT_INITIAL_CAPACITY:HashMap的默认容量:16
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75
threshold:扩容的临界值 = 容量 * 填充因子:16 * 0.75 = 12
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
MIN_TREEIFY_CAPACITY:Bucket中Node被转化为红黑树时最小的Hash表容量:64

二、map区分

key-value是否可为null线程安全是否有序实现方式继承类实现类效率
hashMap不安全无序数组加链表jdk1.8以后增加红黑树
AbstractMap
Map
Cloneable
Serializable
hashTable安全无序和hashmap一样也是散列表
Dictionary
Map

Cloneable
Serializable
linkedHashMap不安全有序在hashmap的基础上加了双向链表
HashMap
Map
Serializable
ConcurrentHashMap安全无序分多个桶减少开销
AbstractMap
ConcurrentMap
Serializable

三、hashTable 

HashTable 与 HashMap 一样,也是链表散列,存储键值对,但 HashTable 继承了 Dictionary 类,实现了 Map、Clonable、Serializable 接口

初始化大小 11 负载因子0.75

public Hashtable() {
    this(11, 0.75f);
}
方法加了synchronized 线程安全 但是效率较低

put 过程:

HashTable的put过程
1、判断value不能为null,若为null抛出异常-》hashtable中value不能为null
2、通过key进行hash获取到key该存储的索引位置
3、该索引位置的链表进行遍历,获取key是否存在(key存在条件 hash相等且通过key.equals判断相等)
4、在存在该key的情况下,将value值进行更新且直接返回
5、key不存在则进行新节点插入逻辑
5.1、扩容考虑:entry节点个数大于阈值 (count>threshold)进行扩容
5.2、新容量大小为:2*table.length+1
5.3、将原哈希表中的数据全部进行重新hash到新的hash表中
5.4、更新插入的key的新的位置
5.5、找到新节点位置,创建entry实体通过头插入将元素插入
和hashMap 的区别:
相同点
1、底层数据结构都为数组+链表
2、key都不能重复
3、插入元素有不能保证插入有序
4、哈希过程通过key进行hash
不同点:
1、安全性问题:
HashMap不能保证线程安全
HashTable能保证线程
2、继承关系:
HashMap继承自AbstractMap
HashTable继承自Dictionary
3、null值问题
HashMap的key和value都可以为null
HashTable的key和value都不能为null
4、扩容方式
HashMap按照2table.length
HashTable按照2table.length+1
5、默认值
HashMap默认数组大小为16
HashTable默认数组大小为11
6、hash算法不同
7、效率不同
HashMap在单线程小效率高
HashTable在单线程小效率低
 

四、linkedHashMap

hashMap的子类,所以hashMap的属性他基本都有,

区别在于,他是有序的;只是加了指针,把元素串联了起来 

原理:双向链表 加hash

 四、set底层原理

set 和list 一样都是Collection 的子类

set 存放的数据不可以重复

三个实现类

hashSet linkedHashSet treeSet AbstractSet

hashSet 特点:元素不允许重复,可以为null,无序的,线程不安全
(1)hashSet 是基于hashMap实现的,默认的构建函数是初始化一个hashMap,

其实就是相当于把 存入HashSet的值,当成了HashMap的key值来存储,value 存的是present对象。

(2)HashSet实现set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元素。

LinkedHashSet 继承HashSet 同时有基于linkedHashMap的实现原理
特点:保留插入顺序

 底层使用LinkedHashMap 来保存元素,加了链表的数据结构功能。

所以特点是在hashSet 的基础上,无序变成了有序的,

代码就几个构造方法,但是是直接向上,调用父类的构造方法,父类hashSet 专门给他的构造方法如下,新建了一个LinkedHashMap,初始大小是16,负载因子0.75;

treeSet  特点:排序

treeSet 的实现原理是利用treeMap

支持自然排序和定制排序  默认自然排序

treeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这种方式就是自然排序。(比较的前提:两个对象的类型相同)

 TreeSet的自然排序是根据集合元素的大小,TreeSet将他们以升序排列。如果需要实现定制排序,例如降序,则可以使用Comparator接口。该接口里包含一个int compare(T o1, T o2)方法,该方法用于比较o1和o2的大小。    如果需要实现定制排序,则需要在创建TreeSet集合对象时,并提供一个Comparator对象与该TreeSet集合关联,由该Comparator对象负责集合元素的排序逻辑。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值