gzdjava集合框架的一些源码类型分析Word文档格式.docx

上传人:b****7 文档编号:22254411 上传时间:2023-02-03 格式:DOCX 页数:14 大小:3.01MB
下载 相关 举报
gzdjava集合框架的一些源码类型分析Word文档格式.docx_第1页
第1页 / 共14页
gzdjava集合框架的一些源码类型分析Word文档格式.docx_第2页
第2页 / 共14页
gzdjava集合框架的一些源码类型分析Word文档格式.docx_第3页
第3页 / 共14页
gzdjava集合框架的一些源码类型分析Word文档格式.docx_第4页
第4页 / 共14页
gzdjava集合框架的一些源码类型分析Word文档格式.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

gzdjava集合框架的一些源码类型分析Word文档格式.docx

《gzdjava集合框架的一些源码类型分析Word文档格式.docx》由会员分享,可在线阅读,更多相关《gzdjava集合框架的一些源码类型分析Word文档格式.docx(14页珍藏版)》请在冰豆网上搜索。

gzdjava集合框架的一些源码类型分析Word文档格式.docx

除了四个历史集合类外,Java2框架还引入了六个集合实现,如下表所示。

接口

实现

历史集合类

Set

HashSet

TreeSet

List

ArrayList

Vector

LinkedList

Stack

Map

HashMap

Hashtable

TreeMap

Properties

集合详解之collection

collevction的实现基础是Object数组,所以他肯定有toArray方法

任何容器,都能将元素放进去、取出来,而且collection没有get()方法,要想从中去除元素,只有遍历了,所以Collection接口提供了iterator方法,此方法返回一个iterator对象,利用iterator接口的接口的方法,对Collection进行遍历。

而iterator接口的方法很少,只有booleanhasNext();

Enext();

voidremove();

集合详解之List

List接口只继承了Collection接口

两种常对List接口的实现

简述

操作特性

成员要求

提供基于索引的对成员的随机访问

提供快速基于索引的成员访问,对头尾的增加删除等最好

任意Object自雷的对象

对任何位置的增加删除支持特别好,但是基于索引的成员访问功能差

任意Object子类的对象

ArrayList简单分析实现原理

ArrayList的3个构造函数

这个构造函数比较重要,但是不常用。

其中intinitialCapacity表示构造这个ArrayList初始列表的容量,理解这个参数的方式得看ArrayList的两个属性,第一个属性

,我们使用elementData[]这个数组来存放集合中的数据,而intinitialCapacity就是这个数组的lengh!

默认值为10!

下面说第二个属性

size表示列表中真是数据的存放个数!

这个构造函数的作用就是把另一个容器对象中的元素放到当前List对象中去!

ElementData[]被容器CtoArray后赋值,然后ArrayList的实际尺寸Size为此时的ElecmentData[]的长度,然后利用elementData[],ArrayList的尺寸Size,和获取的class来创建一个ArrayList!

疑问?

既然ArrayList是基于数组来实现的,那么elementData[]数组的长度是固定的,而怎么能通过Size来最后确定ArrayList尺寸?

既然这样,那就是elementData[]有它的扩容机制!

先说ArrayList是继承了抽象类AbstractList而在这个抽象类中有modcount的变量

并且被初始化为0,这个变量表示对elementData数组进行了多少次操作,比如扩容、清空。

再看源码

首先得到当前elementData 属性的长度oldCapacity。

然后通过判断oldCapacity和mi-nCapacity参数谁大来决定是否需要扩容

如果minCapacity大于oldCapacity,那么我们就对当前的List对象进行扩容。

扩容的的策略为:

取(oldCapacity*3)/2+1和minCapacity之间更大的那个。

然后使用数组拷贝的方法,把以前存放的数据转移到新的数组对象中

如果minCapacity不大于oldCapacity那么就不进行扩容。

集合讲解之Map

Map简单原理

从图中可以知道,他和collection没有一点关系!

下面为Map几种常用实现类的比较

 

保存键值对成员,基于键找值操作,使用compareTo或compare方法对键进行排序

能满足用户对Map的通用需求

键成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

支持对键有序地遍历,使用时建议先用HashMap增加和删除成员,最后从HashMap生成TreeMap;

附加实现了SortedMap接口,支持子Map等要求顺序的操作

键成员要求实现Comparable接口,或者使用Comparator构造TreeMap键成员一般为同一类型。

LinkedHashMap

保留键的插入顺序,用equals方法检查键和值的相等性

成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

注意:

treeMap是通过key来排序的,所以要求Key对象要实现Comparable接口!

HashMap的实现原理

Hash算法和Hash表

Hash算法的意义在于提供了一种快速存取数据的方法,它用一种算法建立键值与真实值之间的对应关系,(每一个真实值只能有一个键值,但是一个键值可以对应多个真实值),这样可以快速在数组等里面存取数据。

HashMap属性1

用来存放键值对的对象Entry数组,也就是Hash表

在Map接口中有内部接口

,用它来保存我们的键值对!

HashMap属性2

当前Map中存放的键值对的个数

HashMap属性3

负载因子,用来决定什么情况下应该对Entry进行扩容

主要构造函数

1. 

首先是判断参数intinitialCapacity和floatloadFactor是否合法

2. 

然后确定Hash表的初始化长度。

确定的策略是:

通过传进来的参数initialCapacity来找出第一个大于它的2的次方的数。

比如说我们传了18这样的一个initialCapacity参数,那么真实的table数组的长度为2的5次方,即32。

之所以采用这种策略来构建Hash表的长度,是因为2的次方的运算对于现代的处理器来说,可以通过一些方法得到更加好的执行效率。

3. 

接下来就是得到重构因子(threshold)了,这个属性也是HashMap中的一个比较重要的属性,它表示,当Hash表中的元素被存放了多少个之后,我们就需要对该Hash表进行重构。

4. 

最后就是使用得到的初始化参数capacity来构建Hash表:

Entry[]table。

如何添加键值对

首先我们判断如果key为null则使用一个常量来代替该key值,该行为在方法maskNull()终将key替换为一个非null的对象k。

计算key值的Hash码:

hash

通过使用Hash码来定位,我们应该把当前的键值对存放到Hash表中的哪个格子中。

indexFor()方法计算出的结果:

i就是Hash表(table)中的下标。

然后遍历当前的Hash表中table[i]格中的链表。

从中判断已否已经存在一样的键(Key)的键值对。

如果存在一样的key的键,那么就用新的value覆写老的value,并把老的value返回

5. 

如果遍历后发现没有存在同样的键值对,那么就增加当前键值对到Hash表中的第i个格子中的链表中。

并返回null。

最后我们看看一个键值对是如何添加到各个格子中的链表中的:

我们先看voidaddEntry(inthash,Objectkey,Objectvalue,intbucketIndex)方法,该方法的作用就用来添加一个键值对到Hash表的第bucketIndex个格子中的链表中去。

这个方法作的工作就是:

创建一个Entry对象用来存放键值对。

添加该键值对----Entry对象到链表中

最后在size属性加一,并判断是否需要对当前的Hash表进行重构。

如果需要就在voidresize(intnewCapacity)方法中进行重构。

之所以需要重构,也是基于性能考虑。

大家可以考虑这样一种情况,假定我们的Hash表只有4个格子,那么我们所有的数据都是放到这4个格子中。

如果存储的数据量比较大的话,例如100。

这个时候,我们就会发现,在这个Hash表中的4个格子存放的4个长长的链表。

而我们每次查找元素的时候,其实相当于就是遍历链表了。

这种情况下,我们用这个Hash表来存取数据的性能实际上和使用链表差不多了。

但是如果我们对这个Hash表进行重构,换为使用Hash表长度为200的表来存储这100个数据,那么平均2个格子里面才会存放一个数据。

这个时候我们查找的数据的速度就会非常的快。

因为基本上每个格子中存放的链表都不会很长,所以我们遍历链表的次数也就很少,这样也就加快了查找速度。

但是这个时候又存在了另外的一个问题。

我们使用了至少200个数据的空间来存放100个数据,这样就造成至少100个数据空间的浪费。

在速度和空间上面,我们需要找到一个适合自己的中间值。

在HashMap中我们通过负载因子(loadFactor)来决定应该什么时候应该重构我们的Hash表,以达到比较好的性能状态。

集合之Set

Set

成员不能重复

外部无序地遍历成员。

外部有序地遍历成员;

附加实现了SortedSet,支持子集等要求顺序的操作

成员要求实现Comparable接口,或者使用Comparator构造TreeSet。

成员一般为同一类型。

LinkedHashSet

外部按成员的插入顺序遍历成员

成员与HashSet成员类似

Java中Set的概念和数学中的集合(set)一致,都表示一个集内可以存放的元素是不能重复的。

前面我们会发现,Set中很多实现类和Map中的一些实现类的使用上非常的相似。

而且前面再讲解Map的时候,我们也提到:

Map中的“键值对”,其中的“键”是不能重复的。

这个和Set中的元素不能重复一致。

我们以HashSet为例来分析一下,会发现其实Set利用的就是Map中“键”不能重复的特性来实现的。

先看看HashSet中的有哪些属性:

再结合构造函数来看看:

通过这些方法,我们可以发现,其实HashSet的实现,全部的操作都是基于HashMap来进行的。

我们看看是如何通过HashMap来保证我们的HashSet的元素不重复性的:

看到这个操作我们可以发现HashSet的巧妙实现:

就是建立一个“键值对”,“键”就是我们要存入的对象,“值”则是一个常量。

这样可以确保,我们所需要的存储的信息之是“键”。

而“键”在Map中是不能重复的,这就保证了我们存入Set中的所有的元素都不重复。

而判断是否添加元素成功,则是通过判断我们向Map中存入的“键值对”是否已经存在,如果存在的话,那么返回值肯定是常量:

PRESENT,表示添加失败。

如果不存在,返回值就为null表示添加成功。

我们再看看其他的方法实现:

了解了这些后,我们就不难理解,为什么HashMap中需要注意的地方,在HashSet中也同样的需要注意。

其他的Set的实现类也是差不多的原理。

至此对于Set我们就应该能够比较好的理解了。

总结:

集合框架中常用类比较

用“集合框架”设计软件时,记住该框架四个基本接口的下列层次结构关系会有用处:

Collection接口是一组允许重复的对象。

Set接口继承Collection,但不允许重复。

List接口继承Collection,允许重复,并引入位置下标。

Map接口既不继承Set也不继承Collection,存取的是键值对

我们以下面这个图表来描述一下常用的集合的实现类之间的区别:

Collection/Map

成员重复性

元素存放顺序(Ordered/Sorted)

元素中被调用的方法

基于那中数据结构来实现的

Uniqueelements

Noorder

equals()

hashCode()

Hash表

Insertionorder

Hash表和双向链表

SortedSet

Sorted

compareTo()

平衡树(Balancedtree)

Allowed

数组

链表

Uniquekeys

Keyinsertionorder/Accessorderofentries

SortedMap

Sortedinkeyorder

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1