Java集合排序及java集合类详解CollectionListMapSet_第1页
Java集合排序及java集合类详解CollectionListMapSet_第2页
Java集合排序及java集合类详解CollectionListMapSet_第3页
Java集合排序及java集合类详解CollectionListMapSet_第4页
Java集合排序及java集合类详解CollectionListMapSet_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Java集合排序及java集合类详解(Collection, List, Set, Map)摘要内容Java里面最重要,最常用也就是集合一部分了。能够用好集合和理解好集合对于做Java程序的开发拥有无比的好处。本文详细解释了关 于Java中的集合是如何实现的,以及他们的实现原理。关键字:Collection , List ,Set , Map,集 合,框架。1 集合框架21.1 集合框架概述21.1.1 容器简介21.1.2 容器的分类41.2 Collection 61.2.1 常用方法61.2.2 迭代器81.3 List 101.3.1 概述101.3.2 常用方法111.3.3 实现原

2、理151.4 Map 181.4.1 概述181.4.2 常用方法181.4.3 Comparable接 口 231.4.4 实现原理241.4.5 覆写 hashCode() 291.5 Set 331.5.1 概述331.5.2 常用方法331.5.3 实现原理381.6 总结:集合框架中常用类比较392 练习403 附录:排序41青菜制作 qq :8339511012/7/2009 5:17 PM1集合框架1.1集合框架概述1.1.1容器简介到目前为止,我们已经学习了如何创建多个不同的对象,定义了这 些对象以后,我们就可以利用它们来做一些有意义的事情。举例来说,假设要存储许多雇员,不同的

3、雇员的区别仅在于雇员 的身份证号。我们可以通过身份证号来顺序存储每个雇员,但 是在内存 中实现呢?是不是要准备足够的内存来存储1000个雇员,然后再将这 些雇员逐一插入?如果已经插入了 500条记录,这时需要插入一个身份 证号较低的新雇员,该怎么办呢?是在内存中将500条记录全部下移后, 再从开头插入新的记录?还是创建一个映射来记住每个对象的位置? 当决定如何存储对象的集合时,必须考虑如下问题。对于对象集合,必须执行的操作主要以下三种:添加新的对象删除对象查找对象我们必须确定如何将新的对象添加到集合中。可以将对象添加到集 合的末尾、开头或者中间的某个逻辑位置。从集合中删除一个对象后,对象集合中

4、现有对象会有什么影响呢? 可能必须将内存移来移去,或者就在现有对象所驻留的内存位置下一个 “洞”。在内存中建立对象集合后,必须确定如何定位特定对象。可建立 一种机制,利用该机制可根据某些搜索条件(例如身份证号)直接定位 到目标对象;否则,便需要遍历集合中的每个对象,直到找到要查找的 对象为止。前面大家已经学习过了数组。数组的作用是可以存取一组数据。 但是它却存在一些缺点,使得无法使用它来比较方便快捷的完成上述应 用场景的要求。1. 首先,在很多数情况下面,我们需要能够存储一组数据的容 器,这一点虽然数组可以实现,但是如果我们需要存储的数据 青菜制作 qq :8339511012/7/2009

5、5:17 PM的个数多少并不确定。比如说:我们需要在容器里面存储某个 应用系统的当前的所有的在线用户信息,而当前的在线用户信 息是时刻都可能在变化的。也就是说,我们 需要一种存储数 据的容器,它能够自动的改变这个容器的所能存放的数据数量 的大小。这一点上,如果使用数组来存储的话,就显 得十分的 笨拙。2. 我们再假设 这样一种场景:假定一个购物网站,经过一段时 间的运行,我们已经存储了一系列的购物活单了,购物活单中 有商品信息。如果我们想要知道这段时间里面有多少种商品被 销售出去了。那么我们就需要一个容器能够自动的过滤掉购物 活单中的关于商品的重复信息。如果使用数组,这也是很难实 现的。3.

6、最后再想想,我们经常会遇到这种情况,我知道某个人的帐 号名称,希望能够进一步了解这个人的其他的一些信息。也就 是说,我们在一个地方存放一些用户信息,我们希望能够通过 用户的帐 号来查找到对应的该用户 的其他的一些信息。再举 个 查字典例子:假设我们希望使用一个容器来存放单词以及对于 这个单词的解释,而当我们想要查找某个单词的意思的时候, 能够根据提供的单词在这个容器中找到对应的单词的解释。如 果使用数组来实现的话,就更加的困难了。为解决这些问题,Java里面就设计了容器集合,不同 的容器集合以 不同的格式保存对象。数学背景在常见用法中,集合(collection )和数学上直观的集(set )

7、的概 念是相同的。集是一个唯一项组,也就是说组中没有重复项。实际上, 集合框架”包含了一个Set接口和许多具体的Set类。但正式的集 概念却比Java 技术提前了 一个世纪,那时英国数学家 George Boo le按逻辑正式的定义了集的概念。大部分人在小学时通过我们熟悉的 维恩图引入的 集的交”和 集的并”学到过一些集的理论。集的基本届性如下:集内只包含每项的一个实例集可以是有 限的,也可 以是无限的可以定义抽象概念集不仅是逻辑学、数 学和计算机科学的基础,对于 商业和系统的日 常应用来说,它也很实用。 连接池”这一概念就是数据库服务器的一个 开放连接集。Web服务器必须管理客户机和连接集。

8、文件描述符提供 了操作系统中另一个集的示例。映射是一种特别的集。它是一种对(pair )集,每个对表示一个元 素到另一元素的单向映射。一些映射示例有:IP地址到域名(DNS )的映射关键字到数 据库记录的映射字典(词到含义的映射)2进制到10进制转换的映射就像集一' 样,映射背后的思想比Java 编程语言' 早的多,甚至比计 算机科学还早。而Java中的Map 就是映射的一种表现形式。1.1.2 容器的分类既然您已经具备了 一些集的理论,您应该能够更轻松的理解 集合框 架”。集合框架”由一组用来 操作对象的接口组成。不同 接口描述不同类型的组。在很大程度上,一旦您理解了接口,您

9、就理解了框架。虽然 您总要创建接口特定的实现,但访问实际集合的方法应该限制在接口方 法的使用上;因此,允许您更改基本的数据结构而不必改变其它代码。 框架接口层次结构如下图所示。Java容器类类库的用途是“保存对象”,并将 其划分为两个不同的 概念:1) Collection 。 一组对立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。青菜制作 qq :8339511012/7/2009 5:17 PM2)Map 。 一组 成对的“键值对”对象。初看起来这似乎应该是一个Collection ,其元素是成对的对象,但是这样的设计实现起 来太笨拙了,丁是我

10、们将Map明确的提取出来形成一个独立的概 念。另一方面,如果使用Collection 表示Map的部分内容,会便 丁查看此部分内容。因此Map 一样容易扩展成多维Map ,无需 增加新的概念,只要让Map中的键值对的每个“值”也是一个M ap即可。Collection和Map的区别在丁容器中每个位置保存的元素个数。Co llection 每个位置只能保存一个元素(对象)。此类容器包括:List , 它以特定的顺序保存一组元素;Set则是元素不能重复。Map保存的是“键值对”,就像一个小型数据库。我们可以通过“键” 找到该键对应的“值”。Collection -对象之间没有指定的顺序,允许重复元

11、素。Set - 对象之间没有指定的顺序,不允许重复元素List - 对象之间有指定的顺序,允许重复元素,并引入位置 下标。Map - 接口用丁保存关键字(Key )和数值(Value )的集 合,集合 中的每个对象加入时都提供数值和关键字。Map接口 既不继承 Set也不继承 Collection。List、Set、Map共同 的实现基础是 Object数组除了四个历史集合类外,Java 2框架还引入了六个集合实现,如卜表所小0接口实现历史集合类SetHashSetTreeSetListArrayListVectorLinkedListStackMapHashMapHashtableTreeM

12、apProperties这里没有 Collection 接口的实现,接下来我们再来看一下下面的这张关丁集合框架的大图:这张图看起来有点吓人,熟悉之后就会发现其实只有三种容器: Map , List和Set ,它们各自有两个三个实现版本。常用的容器用黑色 粗线框表小。点线方框代表“接口 ”,虚线方框代表抽象类,而实线方框代表普 通类(即具体类,而非抽象类)。虚线箭头指出一个特定的类实现了一 个接口(在抽象类的情况下,则是“部分”实现了那个接口)。实线箭 头指出一个类可生成箭头指向的那个类的对象。例如任何集合(Colle ction ) 都能产生一个迭 代器(Iterator ) ,而一个List

13、除了能 生成一 个Listiterator(歹U表迭 代器)夕卜,还能生成一个 普通 迭代 器,因为List正是从集合继承来的.1.2 Collection1.2.1 常用方法Collection 接口用于表示任何对象或元素组。想要尽可能以常规方式 处理一组元素时,就使用这一接口。Collection 在前面的大图也可以看出,它是 List和Set的父类。并且它本身也是一个接口。它定义了作为集合所应该拥有的 一些方法。如下:注意:集合必须只有对象,集合中的元素不能是基本数据类型。Collection 接口支持如添加和除去等基本操作。设法除去一个元素时,如 果这个元素存在,除去的仅仅是集合中此元

14、素的一个实例。boolean add(Object element)boolean remove(Object element)Collection 接口还支持查询操作:int size()boolean isEmpty()boolean contains(Object element)Iterator iterator()组操作:Collection 接口支持的其它操作,要么是作用于元素组的任务, 要么是同时作用于整个集合的任务。boolean containsAll(Collection collection)boolean addAll(Collection collection)青菜制

15、作 qq :8339511012/7/2009 5:17 PMvoid clear() void removeAll(Collection collection)void retainAll(Collection collection)containsAll()方法允许您查找当前集合是否包含了另一个集合的所有元素,即另一个集合是否是当前集合的子集。其余方法是可选的,因为特定的集合可能不支持集合更改。addAll()方法确保另一个集合中的所有元素都被添加到当前的集合中,通常称为并。clear()方法从当前集合中除去所有元素。removeAll()方法类似于clear(),但只除去了元素的一个子集

16、。retainAll()方法类似于removeAll()方法,不过可能感到它所做的与前面正好相反:它从当 前集合中除去不属于另一个集合的元素,即交。我们看一个简单的例子,来了解一下集合类的基本方法的使用:import java.util.*;public classCollectionToArray (public static void main(String口 args) (Collection collection1= new ArrayList();/ 创建一个集合对象collection1.add("000”);/ 添加对象到 Collection 集合中collectio

17、n1.add("111");collection1.add("222”);System.out.println("集合 collection1 的大小:"+collection1.size();System.out.println("集合 collection1 的内容:"+collection1);collection1.remove("000");/ 从集合 collection1 中移除掉"000"这个对象System.out.println("集合 collectio

18、n1 移除 000 后的内容:"+collection1);System.out.println("集合 collection1 中是否包含 000 : "+collection1.contains("000");System.out.println("集合 collection1 中是否包含 111 : "+collection1.contains("111");Collection collection2= new ArrayList();collection2.addAll(collection1)

19、;/ 将 collection1 集合中的元素全部都加到collection2中System.out.println("集合 collection2 的内容:"+collection2);collection2.clear();/ 清空集合 collection1 中的元素System.out.println("集合 collection?是否为空:"+collection2.isEmpty();将集合collectionl转化为数组Object s= collection1.toArray();for (int i=0;i<s.length;i+

20、)(System.out.println(si);运行结果为:collectionl 的大小:3collectionl 的内容:000, 111,222collectionl 移除 000 后的内容:111,222collection1 中是否包含 000 : falsecollection1 中是否包含 111 : true集合 collection2 的内容:111,222集合collection2是否为空 :true 111 222这里需要注意的是,Collection 它仅仅只是一个接口,而我们真正 使用的时候,确是 创建该接口的一个实现类。做为 集合的接口,它定义 了所有届丁集合的类

21、所都应该具有的一些方法。而ArrayList(歹U表)类是集合类的一种实现方式。这里需要一提的是,因为Collection的实现基础是数组,所以有转 换为Object数组的方法:Object toArray()Object toArray(Object a)其中第二个方法Object toArray(Object a)的参数 a应该是集 合中所有存放的对象的类的父类。1.2.2 迭代器任何容器类,都必须有某种方式可以将东西放进去,然后 由某种方 式将东西取出来。毕竟,存 放事物是 容器最基本的工作。对 丁 ArrayLis t, add ()是 插入 对象的 方法,而 get()是取 出元 素

22、的 方式 之一。ArrayL ist很灵活,可以随时选取任意的元素,或使用不同的下标一次选取多个 元素。如果从更高层的角度思考,会发现这里有一个缺点:要使用容器, 必须知道其中元素的确切类型。初看 起来这没有什么不好的,但是 考虑 如下情况:如果原本是ArrayList ,但是后来考虑到容器的特点,你想 换用Set ,应该怎么做?或者你打算写通用的代码,它们只是使用容器, 不知道或者说不关心容器的类型,那么如何才能不重写代码就可以应用 丁不同类型的容器?所以迭代器(Iterator)的概念,也是出丁一种设计模式就是为达成 此目的而形成的。所以Collection不提供get()方法。如果要遍历

23、Collec tin中的元素,就必须用Iterator 。青菜制作 qq :8339511012/7/2009 5:17 PM迭代器(Iterator )本身就是一个对象,它的工作就是遍历并选择 集合序列中的对象,而客户端的程序员不必知道或关心该序列底层的结 构。此外,迭代器通常被称为“轻 量级”对象,创建它的代价小。但是, 它也有一些限制,例如,某些迭代器只能单向移动。Collection 接口 的 iterator() 方法返回一个 Iterator 。 Iterat or和您可能已经熟悉的Enumeration 接口类似。使用Iterator 接 口方法,您可以从头至尾遍历集合,并安全的

24、从底层Collection 中 除去元素。下面,我们看一个对丁迭代器的简单使用:import java.util.ArrayList;mport java.util.Collection;mport java.util.Iterator;publicclass IteratorDemo publicstaticvoid main(String args) Collection collection =new ArrayList();collection.add("s1");collection.add("s2");collection.add("

25、;s3”);Iterator iterator = collection.iterator();/得到一个迭代器 while (iterator.hasNext() / 遍历Object element = iterator.next(); System.out.println("iterator = "+ element); if (collection.isEmpty()System.out.println("collection is Empty!");else System.out.println("collection is not

26、Empty! size="+collection.size(); Iterator iterator2 = collection.iterator(); while (iterator2.hasNext() / 移 除元素Object element = iterator2.next();System.out.println("remove: " +element); |iterator2.remove(); Iterator iterator3 = collection.iterator(); if (!iterator3.hasNext() / 察看是否还有元

27、素System.out.println("还有 元素"); if (collection.isEmpty() 青菜制作 qq :83395110 12/7/2009 5:17 PMSystem.out.println("collection is Empty!");/ 使用 collection.isEmpty()方法 来判断程序的运行结果为:iterator = s1iterator = s2iterator = s3Icollection is not Empty! size=3remove: s1remove: s2 |remove: s3还有元素

28、collection is Empty!可以看到,Java的Collection 的Iterator 能够用来,:1) 使用方法 iterator。 要求容器返回一个Iterator .第一次调用Iterator的next()方法时,它返回集合序歹0的第一个元素。2) 使用next()获得集合序列的中的下一个元素。3) 使用hasNext()检查序列中是否元素。4) 使用remove()将迭代器新返回的元素删除。需要注意的是:方法删除由next方法返 回的最后一个元素,在每次 调用next时,remove方法只能被调用一次。大家看,Java实现 的这个迭 代器的使用就是如此的简单。Iterat

29、or (跌代器)虽然功能简单,但仍然可以帮助我们解决许多问题,同时针 对List还有一个更复杂更高级的ListIterator。您可以在下面的List讲 解中得到进一步的介绍。1.3 List1.3.1 概述前面我们讲述的Collection 接口实际上并没有直接的实现类|。而List是 容器的一种,表示列表的意思。当我们不知道存储的数据有多少的情况,我 们就可以使用List来完成存储数据的工作。例如前面提到的一种场景。我 们想要在保存一个应用系统当前的在线用户的信息。我们就可以使用一个Li st来存储。因为List的最大的特点就是能够自动的根据插入的数据量来动态改变容器的大小。下面我们先看看

30、List接口的一些常用方法。1.3.2 常用方法List就是列表的意思,它是Collection 的一种,即 继承了 Collection接口,以定义一个允许重复项的有序集合。该接口不但能够对列表的一部分进行 处理,还添加了面向位置的操作。List是按对象的进入顺序进行保存对象,而 不做排序或编辑操作。它除了拥有Collection 接口的所有的方法外还拥有一些其 他的方法。面向位置的操作包括插入某个元素或Collection 的功能,还包括获取、 除去或更改元素的功能。在List 中搜索元素可以从列表的头部或尾部开始, 如果找到元素,还将报告元素所在的位置。void add(int inde

31、x, Object element) : 添 加对象 element 至U 位置 inde x上boolean addAll(int index, Collection collection) : 在 index 位 置后添 加容器collection 中所有的元素Object get(int index):取出 下标为index的位置 的元素int indexOf(Object element):查找对象 element 在 List 中第一次出 现的位置int lastIndexOf(Object element):查找对象 element 在 List 中最后出 现的位置Object r

32、emove(int index) : 删 除 index 位置上 的元素Object set(int index, Object element):将 index 位置上 的对象替换为 element 并返 回老的 元素。先看一下下面表格:简述实现操作特性成员要求List提供基丁索引的对成员的随机访问ArrayList提供快速的基丁索引的成员访 问,对尾部成员的增加和删除 支持较好成员可为任意Object子类的对象LinkedList对列表中任何位置的成员的增 加和删除支持较好,但对基丁 索引的成员访问支持性能较差成员可为任意Object子类的对象在 集合框架”中有两种常规的List 实现:A

33、rrayList 和LinkedList 。使用两 种List 实现的哪一种取决丁您特定的需要。如果要支 持随机访问,而不必在除尾部的任何位置插入或除去元素,那么,Arr ayList 提供了可 选的集合。但如果,您要频繁的从列表的中间位置添加和除去元素,而只要顺序的访问列表元素,那么,LinkedList 实现 更好。我们以ArrayList 为例,先看一个简单的例子:例子中,我们把12个月份存放到ArrayList 中,然后用一个循环, 并使用get ()方法将列表中的对象都取出来。而LinkedList 添加了一些处理列表两端元素的方法(下图只显示了新方 法):使用这些新方法,您就可以轻

34、松的把LinkedList 当作一个堆栈、队列或 其它面向端点的数据结构。我们再来看另外一个使用LinkedList 来实现一个简单的队列的例子 import java.util.*;publicclassListExample publicstaticvoid main(String args) LinkedList queue =new LinkedList()queue.addFirst("Bernadine");queue.addFirst("Elizabeth");queue.addFirst("Gene");queue.a

35、ddFirst("Elizabeth");queue.addFirst("Clara" );System.out.println(queue);queue.removeLast();queue.removeLast();System.out.println(queue);运行程序产生了以下输出。请注意,与Set 不同的是List 允许重复。Clara, Elizabeth, Gene, Elizabeth, BernadineClara, Elizabeth, Gene该的程序演示了具体List 类的使用。第一部分,创 建一个由ArrayList支持的L

36、ist 。填充完列表以后,特定条目就得到了。示例的LinkedList部分把LinkedList 当作一个队列,从队列头部添加东西,从尾部除去。List 接口不但以位置友好的方式遍历整个列表,还能处理集合的子集:ListIterator listIterator() :返回 一个 ListIterator 跌代器, 默认开始位置为0Listiterator listIterator(int startindex) :返 回一 个 ListIterat or跌代器,开始位置为startindexList subList(int fromindex, int toindex) :返回一个子歹U表

37、List ,元素存放为从 fromindex至U toindex之前的一个元素。处理 subList() 时,位于fromindex 的元素在子列表中,而位于to index 的元素则不是,提醒这一点很重要。以下for-loop 测试案例大致反 映了这一点:for (int i=fromindex; i<toindex; i+) (/ process element at position i此外,我 们还应该提醒的是:对子列表的更改(如 add() 、remove() 和 set() 调用)对底层List 也有影响。Listiterator 接 口Listiterator接口继承ite

38、rator 接口以支持添 加或更改底层集合中的元素,还支持双向访问。以下源代码演示了列表中的反向循环。请注意Listiterator最初位于列表尾之后(list.size(),因为第一个元素的下标是0。List list =.;Listiterator iterator = list.listiterator(list.size();while (iterator.hasPrevious() (Object element = iterator.previous();/ Process element正常情况下,不用Listiterator改变某次遍历集合元素的方向 一 向前或者向后。虽然在技

39、术上可能实现时,但在previous() 后立刻调用nex t(),返 回的是同一个元素。把调用next() 和previous() 的顺序颠倒一下, 结果相同。我们看一个List的例子:import java.util.*;publicclass ListiteratorTest (publicstaticvoid main(String args) (List list =new ArrayList();list.add("aaa");list.add("bbb");list.add("ccc");"ddd")

40、;list.add(System.out.println("下标 0 开始:"+list.listIterator(0).next();/next()System.out.println("下标 1 开始:"+list.listIterator(1).next();System.out.println("子 List 1-3:"+list.subList(1,3);/子列表ListIterator it = list.listIterator();/默认从下标0开Object=" +it.next();)/set 属性Lis

41、tIterator it1 = list.listIterator();it1.next();it1.set("ooo");ListIterator it2 = list.listIterator(list.size();/下标while (it2.hasPrevious()System.out.println("previous Index="+it2.previousIndex()+ ",Object=" +it2.previous();)程序的执行结果为:下标0开始:aaa下标1开始:bbb子 List 1-3:bbb, ccc

42、next Index=1,Object=aaa|next Index=2,Object=bbb|next Index=3,Object=ccc|next Index=4,Object=ddd |previous Index=4,Object=dddprevious Index=3,Object=cccprevious Index=2,Object=bbbprevious Index=1,Object=aaaprevious Index=0,Object=ooo我们还需要稍微再解释一下add() 操作。添加一个元素会导致新 元素立刻被添加到隐式光标的前面。因此,添加元素后调用previous (

43、)会返回新元素,而调用next()则不起作用,返回添加操作之前的下一个元素。下标的显示方式,如下图所示:对于List的基本用法我们学会了,下面我们来进一步了解一下List的实现 原理,以便价升我们对于集合的理解。1.3.3 实现原理前面已经提了 一下Collection的实现基础都是基丁数组的。下面我们就已ArrayList 为例,简单分析一下ArrayList歹0表的实现方式。首 先,先看下它的构造函数。下列表格是在SUN提供的API中的描述:ArrayList () Constructs an empty list with an initial capacity of ten.Array

44、List ( Collection c)Constructs a list containing the elements of thespecified collection, in the order they are returned by the collection's iterator. ArrayList (int initialCapacity)Constructs an empty list with thespecified initial capacity.其中第一个构造函数ArrayList ()和第二构造函数 ArrayList ( Collectio n c

45、) 是按照Collection 接口文 档所 述,所应该 提供两个构造函数, 一个无参数,一个接受另一个 Collection 。第3个构造函数:ArrayList (int initialCapacity)是 ArrayList 实现的比较重要的构造函数,虽然,我们不常用它,但是某认的构造函数正是调用的该带参数:i nitialCapacity的 构造函数来实现的。 其中参数:initialCapacity表示我们构造的这个ArrayList 列表的初始化容量是多大。如果调用默认的构造 函数,则表示默认调用该参数为initialCapacity =10的方式,来进 行构建一个ArrayLis

46、t 列表对象。为了更好的理解这个initialCapacity参数的概念,我们先看看ArrayList 在Sun 提供的源码中的实现方式。先看一下它的属性有哪些:ArrayList 继承了 AbstractList我们主 要看看 ArrayList 中 的属性就可以了。ArrayList 中主要包含2个属性:private transient Object elementData;private int size;其中 数组:elementData 是列表的实现核心属性:数 组。 我们使用 该数组来进行存放集合中的数据。而我们的初始化参数就是该数组构建时候的长 度,即该数组的length 属性

47、就是initialCapacity参数。Kbys : transient表示被修饰的属性不是对象持久状态的一部分,不会自动的序列化。第2个届性:size 表示列表中真实数据的存放个数。我们再来看一下ArrayList 的构造函数,加深一下ArrayList 是基于数 组的理解。从源码中可以看到默认的构造函数调用的就是带参数的构造函数:public ArrayList(int initialCapacity)不过参数 initialCapacity= 10。我们 主要看ArrayList(int initialCapacity)这个构造函数。可以看至【J :this . elementData

48、= new Object initialCapacity ;我们就是使用的initialCapacity这个参数来创建一个Object 数组。而我们所有的往该集合对象中存放的数据,就是存放到了这个Object 数组中去 了。我们在看看另外一个构造函数的源码:这里,我们先看size() 方法的实现形式。它的作用即是返回size 属性值 的大小。然 后我们再看另外一个构造函数public ArrayList(Collectionc),该构造函数的作用是把另外一个容器对象中的元素存放到当前的List 对象中。可以看到,首先,我们是通过调用另外一个容器对象C的方法size() 来设 置当前的List

49、对象的size 属性的长度大小。接下来,就是对elementData 数组进行初始化,初始化的大小为原 先容器大小的1.1倍。最后,就 是通过使用容器接口中的Object toArray(O bject a) 方法来把当前容器中的对象都存放到新的数组elementDat a 中。这 样就完成了一个ArrayList 的建立。可能大家会存在一个问题,那就是,我们建立的这个ArrayList 是使用 数组来实现的,但是数组的长度一旦被定下来,就不能改变了。而我们在给Ar rayList 对象中添加元素的时候,却没有长度限制。这个时候,ArrayList 中的elementData 属性就必须存在一

50、个需要动态的扩充容量的机制。我们看 下面的代码,它描述了这个扩充机制:这个方法的作用就是用来判断当前的数组是否需要扩容,应该扩容多少。其 中属性:modCount 是继承自父类,它表示当前的对象对elementData 数组进 行了多少次扩容,清空,移除等操作。该属性相当于是一个对于当前List 对 象的一个操作记录日志号。 我们主要看下面的代码实现:1. 首先得 到当前elementData 属性 的长度oldCapacity 。2. 然后通 过判断oldCapacity 和minCapacity 参数谁大来 决定是 否需要扩容如 果 minCapacity 大于oldCapacity ,那

51、么 我们就对当前 的List 对象进行扩容。扩容的的策略为:取(oldCapacity *3)/2 + 1 和minCapacity 之间更大的那个。然后使用数组拷贝的方法,把以前存放的数据转移到新的数组对象中如 果minCapacity 不大于oldCapacity 那 么就不 进行扩 容。下面我们看看上的那个ensureCapacity 方法的是如何使用的:上的两个a d d方法都是往List 中添加元素。每次在添加元素的时候, 我们就需要判断一下,是否需要对于当前的数组进行扩容。我们主要看看 public boolean add(Object o) 方法,可以发现在添 加一个元素到容器中

52、的时候,首先我们会判断是否需要扩容。因为只增加一个元 素,所以扩容的大小判断也就为当前的size+1 来进行判断。然后,就把新添加 的 元素放 到数组elementData 中。第二 个方法 public boolean addAll(Collection c)也是同 样的原理。将新的元素放到elementData 数组之后。同时改变当前List 对象的si ze属性。类似的List 中的其他的方法也都是基于数组进行操作的。大家有兴趣 可以看看源码中的更多的实现方式。最后我们再看看如何判断在集合中是否已经存在某一个对象的:由源码中我 们可以 看到,public boolean contains

53、(Object elem)方法是通过调用public int indexOf(Object elem)方 法来判 断是否在集合中存在某个对象elem。我们看看indexOf 方法的具体实现。首先我们判断一下elem 对象是否为null ,如果为null 的话,那么遍历数组elementData 把第一个出现null 的位置返回。如果elem 不为null 的话,我们也是遍历数组elementData , 并通过调用elem 对象的equals() 方法来得到第一个相等的元素的 位置。这里我们可以发现,ArrayList 中用来判断是否包含一个对象,调用的是 各个对象自己实现的equals()

54、方法。在前面的高级特性里面,我们可以知道:如果要判断一个类的一个实例对象是否等于另外一个对象,那么我们就需要自己 覆写 Object 类 的 public boolean equals(Object obj)方法。如果不覆写该方法的话,那么就会调用Object 的equals() 方法来进行判断。这就相 当于比较两个对象的内存应用地址是否相等了。在集合框架中,不仅仅是List ,所有的集合类,如果需要判断里面是否 存放了的某个对象,都是调用该对象的equals() 方法来进行处理的。1.4 Map1.4.1 概述数学中的映射关系在Java中就是通过Map来实现的。它表示,里面存储的 元素是一个

55、对(pair ),我们通过一个对象,可以在这个映射关系中找到另外一 个和这个对象相关的东西。前面提到的我们对于根据帐号名得到对应的人员的信息,就属于这种情况的 应用。我们讲一个人员的帐户名和这人员的信息作了一个映射关系,也就是说, 我们把帐户名和人员信息当成了一个“键值对”,“键”就是帐户名,“值”就是 人员信息。下面我们先看看Map接口的常用方法。1.4.2 常用方法Map接口不是 Collection 接口的继承|。而是从自己的用于维护键-值 关联的接口层次结构入手。按定义,该接口描述了从不重复的键到值的映射。我们可以把这个接口方法分成三组操作:改变、查询和提供可选视图。改变操作允许您从映

56、射中添加和除去键-值对。键和值都可以为null 。但 是,您不能把 Map作为一个键或值添加给自身。Object put(Object key,Object value):用 来存放一个键-布对Map中Object remove(Object key):根据 key(键),移除一void putAll(Map mapping):将另外一个 Map 中的元素存入当前的Map巾void clear():活空当前 Map中的元素查询操作允许您检查映射内容:Object get(Object key):根据 key(键)取得对应的boolean containsKey(Object key):判 断

57、Map 中是否存在某键(key )boolean containsValue(Object value):判断 Map中是否存在某值(value)int size():返回Map中键-值对的个数boolean isEmpty():判断当前Map是否为空最后一组方法允许您把键或值的组作为集合来处理。public Set keySet():返 回所有 的键(key ),并使 用Set容器存放public Collection values():返回所有的值(Value),并使用Collection 存放public Set entrySet():返回一个实现 Map.Entry 接口的元素Set因为映射中键的集合必须是唯一的,就使用Set 来支持。因为映射中值的 集合可能不唯一,就使用 Collection 来支持。最后一个方法返

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论