深入Java_Java集合_第1页
深入Java_Java集合_第2页
深入Java_Java集合_第3页
深入Java_Java集合_第4页
深入Java_Java集合_第5页
已阅读5页,还剩166页未读 继续免费阅读

下载本文档

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

文档简介

1、Java集合集合学习要点:学习要点:p Java集合概述p Collection和Iterator接口p Set集合p List集合p Queue集合p Java8增强的Map集合p HashSet和HashMap的性能选项p 操作集合的工具类:Collectionsp 烦琐的接口:Enumerationp 本章小结Java集合类是一种特别有用的工具类,可用于存储数量不等集合类是一种特别有用的工具类,可用于存储数量不等的对象,并可以实现常用的数据结构,如栈、队列等。除此之外的对象,并可以实现常用的数据结构,如栈、队列等。除此之外java集合还可用于保存具有映射关系的关联数组。集合还可用于保存具

2、有映射关系的关联数组。Java集合大致集合大致可分为可分为Set、List、Queue和和Map四种体系,其中四种体系,其中Set代表无序、代表无序、不可重复的集合;不可重复的集合;List代表有序、重复的集合;而代表有序、重复的集合;而Map则代表具则代表具有映射关系的集合。有映射关系的集合。Java5中又增加了中又增加了Queue体系集合,代表一体系集合,代表一种队列集合实现。种队列集合实现。第一节第一节 Java集合概述集合概述p 为了保存数量不确定的数据,以及保存具有映射关为了保存数量不确定的数据,以及保存具有映射关系的数据(也称为关联素组),系的数据(也称为关联素组),Java提供了

3、集合类提供了集合类。集合类主要负责保存、盛装其他数据,因此集合。集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。所有的集合类都位于类也被称为容器类。所有的集合类都位于java.util包包下,后来为了处理多线程环境下的并发安全问题,下,后来为了处理多线程环境下的并发安全问题,java5还在还在java.util.concurrent包下提供了一些多线包下提供了一些多线程支持的集合类。程支持的集合类。p 集合类和数组不一样,数组元素既可以是基本数据集合类和数组不一样,数组元素既可以是基本数据类型,又可以是对象(实际上保存的是对象的引用类型,又可以是对象(实际上保存的是对象的引用变量)

4、;而集合只能保存对象。变量);而集合只能保存对象。p J a v a 的 集 合 类 主 要 由 两 个 接 口 派 生 而 出 :的 集 合 类 主 要 由 两 个 接 口 派 生 而 出 :Collection和和Map。Collection接口及其接口及其派生派生类类Map体系的继承树体系的继承树第二节第二节 Collection和和Iteration接口接口Collection接口是接口是List、Set和和Queue接口的父接口,该接口接口的父接口,该接口里定义的方法既可用于操作里定义的方法既可用于操作Set集合,也可用于操作集合,也可用于操作List和和Queue集合。集合。Col

5、lection接口里定义了如下操作集合元素的方法接口里定义了如下操作集合元素的方法。p boolean add(Object o):用于向集合里添加一个元素,如果集合对象被添加操作改变了,则返回true。p boolean addAll(Collection c):该方法把集合c里的所有元素添加到指定集合里。如果集合对象被添加操作改变了,则返回true。p void clear():清除集合里所有元素,将集合长度变为0;p boolean contains(Object o):返回集合里是否包含指定元素。p boolean containsAll(Collection c):返回集合里是否包含

6、集合c里所有元素。p boolean isEmpty(): 返回集合是否为空。当集合长度为0时返回true。否则返回false。p Iterator iterator():返回一个Iterator对象,用于遍历集合里的元素。p boolean remove(Object o):从此 collection 中移除指定元素的单个实例,存在多个只删除第一个。p boolean removeAll(Collection c):移除此 collection 中那些也包含在指定 c中的所有元素,如果删除了一个或一个以上,则返回true。p boolean retainAll(Collection c):从

7、集合中删除集合c里不包含的元素(相当于把调用该方法的集合变成该集合和集合c的交集),如果该操作改变了调用该方法的集合,则该方法返回true。p int size():该方法返回集合里元素的个数。p Object toArray(): 该方法把集合转换成一个数组,所有的集合元素变成对应的数组元素。小练习:小练习:因为所有的因为所有的Collection实现类实现类都重写了都重写了toString()方法,该方法,该方法可以一次性输出集合中所方法可以一次性输出集合中所有元素。有元素。上面程序中创建了两个上面程序中创建了两个Collection对象,一个是对象,一个是c集集合,一个是合,一个是boo

8、ks集合,其中集合,其中c集合是集合是ArrayList,而,而books集合是集合是HashSet。虽然他们使用的实现类不同,。虽然他们使用的实现类不同,但当把他们当成但当把他们当成Collection来使用时,使用来使用时,使用add, remove, clear等方法完全没有任何区别。等方法完全没有任何区别。1. 使用使用Lambda表达式遍历集合表达式遍历集合java8为为Iterable接口新增了一个接口新增了一个forEach (Consumer action)默认方法,该方法所需参数的类型是一个函数默认方法,该方法所需参数的类型是一个函数式接口,而式接口,而Iterable接口是

9、接口是Collection接口的父接口,接口的父接口,因此因此Collection集合也可以直接调用该方法。集合也可以直接调用该方法。当程序调用当程序调用Iterable的的forEach(Consumer action)遍遍历集合元素时,程序会依次将集合元素传给历集合元素时,程序会依次将集合元素传给Consumer的的accept(T,t)方法(该接口中唯一的抽象方法)。)方法(该接口中唯一的抽象方法)。正因为正因为Consumer是函数式接口,因此可以使用是函数式接口,因此可以使用Lambda表达式来遍历集合元素。表达式来遍历集合元素。2. 使用使用foreach循环遍历集合元素循环遍历集

10、合元素除了可以使用除了可以使用Iterator接口迭代访问接口迭代访问Collection集合里集合里的元素之外,使用的元素之外,使用Java5提供的提供的foreach循环迭代访问循环迭代访问集合元素更加便捷。集合元素更加便捷。Collection books = new HashSet();books.add(JavaEE);books.add(Android);/使用foreach循环来迭代访问Collection集合元素for(Object obj:books)String book = (String)obj;System.out.println(book);3. 使用使用Java8

11、新增的新增的Predicate操作集合操作集合Java8为为Collection集合新增了一个集合新增了一个removeIf(Predicate filter)方法,该方法见鬼批量删除符合)方法,该方法见鬼批量删除符合filter条件的所有元素。该方法需要一个条件的所有元素。该方法需要一个Predicate(谓词谓词)对对象作为参数,象作为参数,Predicate也是函数式接口,因此可是用也是函数式接口,因此可是用Lambda表示式作为参数。表示式作为参数。4.使用使用Java8新增的新增的Stream操作集合操作集合Java8还新增了还新增了Stream、InStream、LongStrea

12、m、DoubleStream等流式等流式API,这些,这些API代表多个支持串代表多个支持串行和并行聚集操作的元素。行和并行聚集操作的元素。Stream是一个通用的流接是一个通用的流接口,而口,而IntStream、LongStream、DoubleStream则则代表元素类型为代表元素类型为int、long、double的流。的流。Java8还为上面每个流式还为上面每个流式API提供了对应的提供了对应的Builder,例如,例如Stream.Builder, IntStream.Builder, LongBuilder, DoubleStream.Builder, 开发者可以通开发者可以通过

13、这些过这些Builder来创建对应的流。来创建对应的流。独立使用独立使用Stream的步骤如下:的步骤如下: 使用使用Stream或或XXXStream的的builder()类方法创()类方法创建建Stream对应的对应的Builder。 重复调用重复调用Builder的的add()方法向该流中添加多个()方法向该流中添加多个元素。元素。 调用调用Builder的的builder()方法获取该流中添加多个()方法获取该流中添加多个元素。元素。 调用调用Stream的聚集方法。的聚集方法。实例:实例:注意:注意:IntStream的聚集方法只能执行一次。的聚集方法只能执行一次。Stream提供了

14、大量的方法进行聚集操作,这些方法既提供了大量的方法进行聚集操作,这些方法既可以是可以是“中间的中间的”(intermediate),也可以是也可以是“末端的末端的”(terminal)。)。中间方法:中间操作允许流保持打开状态,并允许直中间方法:中间操作允许流保持打开状态,并允许直接调用后续方法。上面程序中的接调用后续方法。上面程序中的map()方法就是中间方方法就是中间方法。中间方法的返回值是另外一个流。法。中间方法的返回值是另外一个流。末端方法:末端方法是对流的最终操作,当对某个末端方法:末端方法是对流的最终操作,当对某个Stream执行末端方法后,该流将会被执行末端方法后,该流将会被“消

15、耗消耗”且不可且不可再用。上面程序的再用。上面程序的sum(),count(),average()等就是末端等就是末端流的方法还有如下两个特征:流的方法还有如下两个特征: 有状态的方法:这种方法会给流增加一些新的属性有状态的方法:这种方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量、保证元素,比如元素的唯一性、元素的最大数量、保证元素以排序的方式被处理等。有状态的方法往往需要更以排序的方式被处理等。有状态的方法往往需要更大的性能开销。大的性能开销。 短路方法:短路方法可以尽早结束对流的操作,不短路方法:短路方法可以尽早结束对流的操作,不必检查所有的元素。必检查所有的元素。介绍一下介

16、绍一下Stream常用的方法:常用的方法:p filter(Predicate predicate):过滤过滤Stream中所有不符中所有不符合合predicate的元素。的元素。p mapToXxx(ToXxxFunction mapper):使用使用ToXxxFunction对流中的元素执行一对一的转换。对流中的元素执行一对一的转换。p peek(Consumer action):依次对每个元素执行一些依次对每个元素执行一些操作,该方法返回的流与原有流包含相同的元素。操作,该方法返回的流与原有流包含相同的元素。该方法主要用于调试。该方法主要用于调试。p distinct():该方法用于排序

17、流中所有重复的元素(:该方法用于排序流中所有重复的元素(判断元素重复的标准是使用判断元素重复的标准是使用equals()比较返回比较返回true)。这是一个有状态的方法。这是一个有状态的方法。p sorted():该方法用于保证流中的元素在后续的访问该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法。中处于有序状态。这是一个有状态的方法。p limit(long maxSize):该方法用于保证对该流的后续该方法用于保证对该流的后续访问中最大允许访问的元素个数。这是一个有状态访问中最大允许访问的元素个数。这是一个有状态的、短路的方法。的、短路的方法。Stream常用的末端

18、方法常用的末端方法p forEach(Consumer action):遍历流中所有元素,遍历流中所有元素,对每个元素执行对每个元素执行action。p toArray():将流中所有元素转换为一个数组。将流中所有元素转换为一个数组。p reduce():该方法有三个重载的版本,都用于通过某该方法有三个重载的版本,都用于通过某种操作来合并流中的元素。种操作来合并流中的元素。p min():返回流中所有元素的最小值。:返回流中所有元素的最小值。p max():返回流中所有元素的最大值。:返回流中所有元素的最大值。p count():返回流中所有元素的数量。返回流中所有元素的数量。p anyMat

19、ch(Predicate predicate):判断流中是否至:判断流中是否至少包含一个元素符号符合少包含一个元素符号符合Predicate条件。条件。p allMatch(Prediacate predicate):判断流中是否每个判断流中是否每个元素都符合元素都符合Predicate条件。条件。p noneMatch(Predicate predicate):判断流中是否所判断流中是否所有元素都不符合有元素都不符合Predicate条件。条件。p findFirst():返回流中的第一个元素。返回流中的第一个元素。p findAny():返回流中的任意一个元素。返回流中的任意一个元素。除此

20、之外,除此之外,Java 8 允许使用流式允许使用流式API来操作集合,来操作集合,Collection接口提供了一个接口提供了一个Stream()默认方法,该方法默认方法,该方法可返回该集合对应的流,接下来计科通过流式可返回该集合对应的流,接下来计科通过流式API来操来操作集合元素。由于作集合元素。由于Stream可以对集合元素进行整体的可以对集合元素进行整体的聚集操作,因此聚集操作,因此Stream极极大地丰富了集合的功能。大地丰富了集合的功能。实例:实例:第三节第三节 Set集合集合set集合类似一个罐子,程序可以一次把对象丢进集合类似一个罐子,程序可以一次把对象丢进set集合,而集合,

21、而set集合通常不能记住元素的添加顺序。集合通常不能记住元素的添加顺序。Set集集合与合与Collection基本相同,没有提供任何额外的方法。基本相同,没有提供任何额外的方法。实际上实际上Set就是就是Collection,只是行为略有不同。,只是行为略有不同。set集合不允许包含相同元素,如果试图把两个相同的集合不允许包含相同元素,如果试图把两个相同的元素加入同一个元素加入同一个Set集合中,则添加操作失败,集合中,则添加操作失败,add()方方法返回法返回false,且新元素不会被加入。,且新元素不会被加入。上面介绍的是上面介绍的是set集合的通用知识,因此完全适合后面集合的通用知识,因

22、此完全适合后面介绍的介绍的HashSet、TreeSet和和EnumSet三个实现类。只三个实现类。只是三个实现类还各有特色。是三个实现类还各有特色。1.HashSet类类HashSet是是set接口的典型实现,大多数时候使用接口的典型实现,大多数时候使用Set集合时就是使用这个实现类。集合时就是使用这个实现类。HashSet按按Hash算法来算法来存储集合中的元素,因此据很好的存储和查找性能。存储集合中的元素,因此据很好的存储和查找性能。HashSet具有以下特点:具有以下特点:p 不能保证元素的排列顺序,顺序可能与添加顺序不不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变

23、化。同,顺序也有可能发生变化。p HashSet不是同步的,如果多个线程同时访问一个不是同步的,如果多个线程同时访问一个HashSet,假设有两个或者两个以上线程同时修改,假设有两个或者两个以上线程同时修改了了HashSet集合时,必须通过代码来保证其同步。集合时,必须通过代码来保证其同步。p 集合元素值可以是集合元素值可以是null。当向当向HashSet集合中存入一个元素时,集合中存入一个元素时,HashSet会调会调用 该 对 象 的用 该 对 象 的 h a s h C o d e ( ) 方 法 来 得 到 该 对 象 的方 法 来 得 到 该 对 象 的hashCode()值,然后

24、根据该值,然后根据该hashCode值决定该对象值决定该对象在在HashSet中的存储位置。如果有两个元素通过中的存储位置。如果有两个元素通过equals()方法比较返回方法比较返回true,但它们的但它们的hasCode()方法返方法返回值不同,回值不同,HashSet将会把他们存储在不同的位置,依将会把他们存储在不同的位置,依然可以添加成功然可以添加成功。也就是说,也就是说,HashSet集合判断两个元素相等的标准是集合判断两个元素相等的标准是两个对象通过两个对象通过equals()方法比较相等,并且两个对象的方法比较相等,并且两个对象的hashCode()方法返回值也相等。方法返回值也相

25、等。如果两个对象的如果两个对象的hashCode()方法返回的方法返回的hasCode值相同,但他们通过值相同,但他们通过equals()方法比较返回方法比较返回false时更加时更加麻烦:因为两个对象的麻烦:因为两个对象的hasCode()值相同,值相同,HashSet将将试图把他们保存在同一个位置,但又不行(否则将只剩试图把他们保存在同一个位置,但又不行(否则将只剩下一个对象),所以实际上会在这个位置用链式结构来下一个对象),所以实际上会在这个位置用链式结构来保存多个对象;而保存多个对象;而HashSet访问集合元素时也是根据元访问集合元素时也是根据元素的素的hashCode值来快速定位的

26、,如果值来快速定位的,如果HashSet中两个中两个以上的元素具有相同的以上的元素具有相同的hashCode值,将会导致性能下值,将会导致性能下降。降。如果两个对象通过如果两个对象通过equals()方法返回方法返回true,但这两,但这两个对象的个对象的hashCode()返回不同的返回不同的hasCode()值时,这值时,这将导致将导致HashSet会把这两个对象保存在会把这两个对象保存在Hash表中的不表中的不同位置,从而使两个对象都可以添加成功,这就与同位置,从而使两个对象都可以添加成功,这就与Set集合的规则冲突了。集合的规则冲突了。如果需要把某个类的对象保存到如果需要把某个类的对象

27、保存到HashSet集合中,集合中,重写这个类的重写这个类的equals()方法和方法和hashCode()方法时,应方法时,应该尽量保证两个对象通过该尽量保证两个对象通过equals()方法比较返回方法比较返回true时时,它们的,它们的hasCode()方法返回值也相同。方法返回值也相同。HashSet中每个能存储元素的中每个能存储元素的“槽位槽位”(slot)通)通常称为常称为“桶桶”(bucket),如果有多个元素的),如果有多个元素的hashCode值相同,但它们通过值相同,但它们通过equals()方法比较返回方法比较返回false,就需要在一个,就需要在一个“桶桶”里放多个元素,

28、这样就会里放多个元素,这样就会导致性能下降。导致性能下降。重写重写hashCode()方法的基本规则方法的基本规则p 在 程 序 运 行 过 程 中 , 同 一 个 对 象 多 次 调 用在 程 序 运 行 过 程 中 , 同 一 个 对 象 多 次 调 用hashCode()方法应该返回相同的值。方法应该返回相同的值。p 当两个对象通过当两个对象通过equals()方法返回方法返回true时,这两个对时,这两个对象的象的hashCode()方法应该返回相同的值。方法应该返回相同的值。p 对象中用作对象中用作equals()方法比较标准的实例变量,都应方法比较标准的实例变量,都应该用于计算该用

29、于计算hashCode重写重写hashCode的一般步骤的一般步骤1.把对象内每个有意义的实例变量(即每个参与把对象内每个有意义的实例变量(即每个参与equals()方法比较标准的实例变量)计算出一个方法比较标准的实例变量)计算出一个int类型类型的的hasCode值。值。hashCode的计算方式的计算方式实例变量类型实例变量类型计算方式计算方式实例变量类型实例变量类型计算方式计算方式booleanhashCode=(f?0:1)floathashCode=Float.floatToIntBirs(f)整数类型(byte,short, char,int)hashCode=(int)fdoub

30、lelong1=Double.doubleToLongBits(f)hashCode=(int)(1(132);longhashCode=(int)(f(f32)引用类型hashCode=f.hashCode()2. 用第一步计算出来的多个用第一步计算出来的多个hashCode值组合计算出值组合计算出一个一个hashCode值返回。值返回。例如:例如:return f1.hashCode()+(int)f2;为了避免直接相加产生偶然相等(两个对象的为了避免直接相加产生偶然相等(两个对象的f1,f2实实例变量并不相等例变量并不相等,但他们的但他们的hashCode的和恰好相等),的和恰好相等),

31、可以通过为各实例变量的可以通过为各实例变量的hashCode值乘以任意一个质值乘以任意一个质数再相加。例如如下代码:数再相加。例如如下代码:return f1.hashCode()*19+(int)f2*31;如果想如果想HashSet中添加一个可变对象后,后面程序修中添加一个可变对象后,后面程序修改了该可变对象的实例变量,则可能导致它与集合中的改了该可变对象的实例变量,则可能导致它与集合中的其他元素相同(即两个对象通过其他元素相同(即两个对象通过equals()方法比较返回方法比较返回true,两个对象的,两个对象的hashCode值也相等),这就有可能值也相等),这就有可能导致导致Hash

32、Set中包含两个相同的对象。中包含两个相同的对象。实例实例由上面的例子可见,当程序把可变对象添加到由上面的例子可见,当程序把可变对象添加到HashSet中之后,尽量不要去修改该集合元素中参与计中之后,尽量不要去修改该集合元素中参与计算算hashCode()、equals()的实例变量,否则将会导致的实例变量,否则将会导致HashSet无法正确操作这些集合元素。无法正确操作这些集合元素。2. LinkedHashSet类类HashSet还有一个子类还有一个子类LinkedHashSet,LinkedHashSet集合也是根据元素的集合也是根据元素的hashCode值来决值来决定元素的存储位置,但

33、它同时使用链表维护元素的次序定元素的存储位置,但它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。也就是,这样使得元素看起来是以插入的顺序保存的。也就是说,当遍历说,当遍历LinkedHashSet集合里的元素时,集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里将会按元素的添加顺序来访问集合里的元素。的元素。LinkedHashSet需要维护元素的插入顺序,因此性需要维护元素的插入顺序,因此性能略低于能略低于HashSet的性能,但在迭代访问的的性能,但在迭代访问的Set里的全里的全部元素是有很好的性能,因为它以链表来维护内部顺序部元素是有很好的性

34、能,因为它以链表来维护内部顺序。实例实例输入输入LinkedHashSet集合的元素时,元素的顺序总是集合的元素时,元素的顺序总是与添加顺序一致。与添加顺序一致。3. TreeSet类类TreeSet是是SortedSet接口的实现类,正如接口的实现类,正如SortedSet名字所暗示的,名字所暗示的,TreeSet可以确保集合元素可以确保集合元素处于排序状态。与处于排序状态。与HashSet集合相比,集合相比,TreeSet还提供还提供了几个额外的方法:了几个额外的方法:p Comparator comparator():如果如果TreeSet采用了定采用了定制 排 序 , 则 该 方 法

35、返 回 定 制 排 序 所 使 用 的制 排 序 , 则 该 方 法 返 回 定 制 排 序 所 使 用 的Comparator();如果;如果TreeSet采用了自然排序,则采用了自然排序,则返回返回null。p Object first():返回集合中的第一个元素。返回集合中的第一个元素。p Object last():返回集合中的最后一个元素。返回集合中的最后一个元素。p Object lower(Object e):返回集合中位于指定元素返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,参考元之前的元素(即小于指定元素的最大元素,参考元素不需要是素不需要是TreeSet集合里

36、的元素)。集合里的元素)。p Object higher(Object e):返回集合中为与指定元素返回集合中为与指定元素之后的元素(即大于指定元素的最小元素,参考元之后的元素(即大于指定元素的最小元素,参考元素不需要是素不需要是TreeSet集合里的元素)。集合里的元素)。p SortedSet subSet(Object fromElement, Object t o E l e m e n t ) : 返 回 此返 回 此 S e t 的 子 集 合 , 范 围 从的 子 集 合 , 范 围 从fromElement(包含包含)到)到toElement(不包含)。(不包含)。p Sort

37、edSet headSet(Object toElement):返回此返回此Set的子集,由小于的子集,由小于toElement的元素组成。的元素组成。p SortedSet tailSet(Object fromElement):返回此返回此Set的子集,由大于或等于的子集,由大于或等于formElement的元素组成的元素组成。提示:表面上看起来这些方法很多,其实他们很简单:因为提示:表面上看起来这些方法很多,其实他们很简单:因为TreeSet中的元素是有序的,所以增加了访问第一个,前一个,中的元素是有序的,所以增加了访问第一个,前一个,后一个,最后一个元素的方法,并提供了三个从后一个,最

38、后一个元素的方法,并提供了三个从TreeSet中截取中截取子子TreeSet的方法。的方法。练习练习与与HashSet集合采用集合采用Hash算法来决定元素的存储位算法来决定元素的存储位置不同,置不同,TreeSet采用红黑树的数据结构来春初集合元采用红黑树的数据结构来春初集合元素。那么素。那么TreeSet进行排序的规则是怎么样的呢?进行排序的规则是怎么样的呢?TreeSet支持两种排序方法:自然排序和定制排序。在支持两种排序方法:自然排序和定制排序。在默认情况下,默认情况下,TreeSet采用自然排序采用自然排序。自然排序自然排序TreeSet会调用集合元素的会调用集合元素的compare

39、To(Object obj)方法来比较元素之间的大小关系,然后将集合元素方法来比较元素之间的大小关系,然后将集合元素按升序排列,这种方法就是自然排序。按升序排列,这种方法就是自然排序。java提供了一个提供了一个Comparable接口,该接口里定义接口,该接口里定义了一个了一个compareTo(Object obj)方法,该方法返回一个方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小。当一个对象调用该方法口的类的对象就可以比较大小。当一个对象调用该方法与 另 一 个 对 象 进 行 比 较 时 ,

40、 例 如与 另 一 个 对 象 进 行 比 较 时 , 例 如pareTo(obj2),如果该方法返回,如果该方法返回0,则表明这,则表明这两个对象相等;如果该方法返回一个正整数,则表明两个对象相等;如果该方法返回一个正整数,则表明obj1obj2;如果该方法返回一个负整数,则表明如果该方法返回一个负整数,则表明obj1o2;如果该方法返回;如果该方法返回0,则表,则表明明01=02;如果该方法返回负整数,则表明如果该方法返回负整数,则表明o102;如果需要实现定制排序则需要在创建如果需要实现定制排序则需要在创建TreeSet集合对象时,集合对象时,提供一个提供一个Comparator对象与该

41、对象与该TreeSet集合关联,由该集合关联,由该Comparator对象负责集合元素的排序逻辑。由于对象负责集合元素的排序逻辑。由于Comparator是一个函数式接口,因此,可以使用是一个函数式接口,因此,可以使用Lambda表达式来代替表达式来代替Comparator表达式。表达式。实例实例从大到小排序:从大到小排序:上 面 程 序 中 粗 体 字 部 分 使 用 了 目 标 类 型 为上 面 程 序 中 粗 体 字 部 分 使 用 了 目 标 类 型 为Comparator的的Lambda表达式,它负责表达式,它负责tsSet集合的排集合的排序。所以当把序。所以当把M对象添加到对象添加

42、到ts集合中时,无须集合中时,无须M类实现类实现Comparator接口,因为此时接口,因为此时TreeSet无须通过无须通过M对象对象本身来比较大小,而是由与本身来比较大小,而是由与TreeSet关联的关联的Lambda表表达式负责集合元素的排序。达式负责集合元素的排序。注意:注意:当通过当通过Comparator对象(或对象(或Lambda表达式)来实表达式)来实现现TreeSet的定制排序时,依然不可以向的定制排序时,依然不可以向TreeSet中添中添加类型不同的对象,否则会引发加类型不同的对象,否则会引发ClassCastException异常,使用定制排序时,异常,使用定制排序时,T

43、reeSet对集合元素排序不管对集合元素排序不管集合元素本省的大小,而是由集合元素本省的大小,而是由Comparator对象(或对象(或Lambda表达式)负责集合元素的排序规则。表达式)负责集合元素的排序规则。TreeSet判断两个元素相等的标准是:通过判断两个元素相等的标准是:通过Comparator(或(或Lambda表达式)比较连个元素返回了表达式)比较连个元素返回了0,这样,这样TreeSet不会把第二个元素添加到集合中。不会把第二个元素添加到集合中。4. EnumSet类类EnumSet是一个专为枚举类设计的集合类,是一个专为枚举类设计的集合类,EnumSet中的所有元素都必须是指

44、定枚举类型的枚举中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建值,该枚举类型在创建EnumSet时显式或隐式的地指时显式或隐式的地指定。定。EnumSet的集合元素也是有序的,的集合元素也是有序的,EnumSet以枚以枚举值在举值在Enum类内的定义顺序来决定集合元素的顺序。类内的定义顺序来决定集合元素的顺序。EnumSet在内部以位向量的形式存储,这种存储形在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此式非常紧凑、高效,因此EnumSet对象占用内存很小对象占用内存很小,而且运行效率很好。尤其是进行批量操作(如调用,而且运行效率很好。尤其是进行批量操作(如调用cont

45、ainsAll()和和retainAll())时,如果其参数也是)时,如果其参数也是EnumSet集合,则该批量操作的执行速度也非常快。集合,则该批量操作的执行速度也非常快。EnumSet集合不允许加入集合不允许加入null元素,如果试图插入元素,如果试图插入null元素,元素,EnumSet将抛出将抛出NullPointerException异异常。如果只是想判断常。如果只是想判断EnumSet是否包含是否包含NULL元素或试元素或试图删除图删除null元素都不会抛出异常,只是删除操作将返回元素都不会抛出异常,只是删除操作将返回false,因为没有任何,因为没有任何NULL元素被删除。元素被

46、删除。EnumSet类没有暴露任何构造器来创建该类的实例类没有暴露任何构造器来创建该类的实例,程序应该通过他提供的类方法来创建,程序应该通过他提供的类方法来创建EnumSet对象对象。E n u m S e t 类 提 供 了 如 下 常 用 的 类 方 法 来 创 建类 提 供 了 如 下 常 用 的 类 方 法 来 创 建EnumSet对象。对象。p EnumSet allOf(Class elementType):创建一个包含创建一个包含指定枚举类里所有枚举值得指定枚举类里所有枚举值得EnumSet集合。集合。p EnumSet complementOf(EnumSet s):创建一个其

47、创建一个其元素类型与指定元素类型与指定EnumSet里元素类型相同的里元素类型相同的EnumSet集合,新集合,新EnumSet集合包含原集合包含原EnumSet集合所不包含的、此枚举类剩下的枚举值。集合所不包含的、此枚举类剩下的枚举值。p EnumSet copyOf(Collection c):使用一个普通集合使用一个普通集合来创建来创建EnumSet集合。集合。p EnumSet copyOf(EnumSet s):创建一个与指定创建一个与指定EnumSet具有相同元素类型、相同集合元素的具有相同元素类型、相同集合元素的EnumSet集合。集合。p EnumSet noneOf(Clas

48、s elementType):创建一个创建一个元素类型为指定枚举类型的空元素类型为指定枚举类型的空EnumSet。p EnumSet of(E first, E. rest):创建一个包含一个或创建一个包含一个或多个枚举值的多个枚举值的EnumSet集合,传入的多个枚举值必集合,传入的多个枚举值必须属于同一个枚举类。须属于同一个枚举类。p EnumSet range(E from, E to):创建一个包含从:创建一个包含从from枚举值到枚举值到to枚举值范围内所有枚举值的枚举值范围内所有枚举值的EnumSet集合。集合。实例实例除了以上实例的方法,还可以复制另一个除了以上实例的方法,还可以

49、复制另一个EnumSet集合中的所有元素来创建新的集合中的所有元素来创建新的EnumSet集合,或者复集合,或者复制另一个制另一个Collection集合中的所有元素来创建新的集合中的所有元素来创建新的EnumSet集合。当复制集合。当复制Collection集合中的所有元素集合中的所有元素来创建新的来创建新的EnumSet集合是,集合是,要求要求Collection集合中集合中的所有元素必须是同一个枚举类型的枚举值的所有元素必须是同一个枚举类型的枚举值,否则就会,否则就会发生发生ClassCastException异常。异常。实例实例5. 各各Set实现类的性能分析实现类的性能分析HashS

50、et和和TreeSet是是Set的两个典型实现,到底如的两个典型实现,到底如何选择何选择HashSet和和TreeSet呢?呢?HashSet的性能总是比的性能总是比TreeSet好(特别是最常用的添加、查询元素等操作)好(特别是最常用的添加、查询元素等操作),因为,因为TreeSet需要额外的红黑树算法来维护集合元素需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保存排序的的次序。只有当需要一个保存排序的Set是,才应该使是,才应该使用用TreeSet,否则都应该使用,否则都应该使用HashSet。HashSet还有一个子类:还有一个子类:LinkedHashSet,但它只,但它只能

51、保存同一个枚举类值作为集合元素。能保存同一个枚举类值作为集合元素。必须指出的是,必须指出的是,set的三个实现类的三个实现类HashSet、TreeSet和和EnumSet都是线程不安全的。如果有多个线都是线程不安全的。如果有多个线程同时访问一个程同时访问一个Set集合,并且有超过一个线程修改了集合,并且有超过一个线程修改了该该Set集合,则必须手动保证该集合,则必须手动保证该Set集合的同步性。通常集合的同步性。通常可以通过可以通过Collection工具类的工具类的synchronizedSortedSet方法来方法来“包装包装”该该Set集合。此操作最好在创建时进行集合。此操作最好在创建

52、时进行,以防止对,以防止对Set集合的意外非同步访问。例如:集合的意外非同步访问。例如:SortedSet s = Collections.synchronizedSortedSet (new TreeSet(.);第四节第四节 List集合集合List集合代表一个元素有序、可重复的集合,集合集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。中每个元素都有其对应的顺序索引。List集合允许使用集合允许使用重复元素,可以通过索引来访问来访问指定的集合元素重复元素,可以通过索引来访问来访问指定的集合元素。List集合默认按元素的添加顺序设置元素的索引。集合默认按元素的添加顺序

53、设置元素的索引。1. Java 8 改进的改进的List接口和接口和ListIterator接口接口List作为作为Collection接口的子接口,当然可以使用接口的子接口,当然可以使用Collection接口里的全部方法。而且由于接口里的全部方法。而且由于List是有序集是有序集合,因此合,因此List集合里增加了一些根据索引来操作集合元集合里增加了一些根据索引来操作集合元素的方法。素的方法。p void add(int index, Object element):将元素将元素element插入到插入到List集合的集合的index处。处。p boolean addAll(int ind

54、ex, Collection c):将集合将集合c所包含的所有元素都插入到所包含的所有元素都插入到List集合的集合的index处。处。p Object get(int index):返回集合返回集合index索引处的元素索引处的元素。p int indexOf(Object o):返回对象返回对象o在在List集合中第一集合中第一次出现的位置索引。次出现的位置索引。p int indexOf(Object o):返回对象返回对象o在在List集合中第一集合中第一次出现的位置索引。次出现的位置索引。p int lastIndexOf(Object o):返回对象返回对象o在在List集合中集合

55、中最后一次出现的位置索引。最后一次出现的位置索引。p Object remove(int index):删除并返回删除并返回index索引处索引处的元素。的元素。p Object set(int index, Object element):将将index索索引处的元素替换成引处的元素替换成element对象,返回被替换的旧元对象,返回被替换的旧元素。素。p List subList(int fromIndex, int toIndex):返回从索返回从索引引fromIndex(包含包含)到索引到索引toIndex(不包含)处所(不包含)处所有集合元素组成的子集合。有集合元素组成的子集合。除此

56、之外,除此之外,java8还为还为List接口添加了如下两个默认方接口添加了如下两个默认方法:法:p void replaceAll(UnaryOperator operator):根据根据operator指定的计算规则重新设置指定的计算规则重新设置List集合的所有元集合的所有元素。素。p void sort(Comparator c):根据根据Comparator参数对参数对List集合的元素排序。集合的元素排序。List的基本用法的基本用法程序试图返回新字符串对象在程序试图返回新字符串对象在List集合中的位置,集合中的位置,实际上实际上List集合中并未包含该字符串对象。因为集合中并未

57、包含该字符串对象。因为List集集合添加对象时通过合添加对象时通过new关键字创建的新字符串对象,两关键字创建的新字符串对象,两个对象显然不是同一对象,但个对象显然不是同一对象,但List的的indexOf方法依然方法依然可以饭后可以饭后2。List判断两个对象相等的标志是什么呢?判断两个对象相等的标志是什么呢?List判断两个对象相等只要通过判断两个对象相等只要通过equals()方法比较方法比较返回返回true即可。即可。实例实例equals()方法返回方法返回true,则表明两个元素相等,就会把第一个元素删除。,则表明两个元素相等,就会把第一个元素删除。注意注意当调用当调用List的的s

58、et(int index, Object element)方法方法来改变来改变List集合指定索引处的元素时,指定的索引必须集合指定索引处的元素时,指定的索引必须是是List集合的有效索引。例如集合长度是集合的有效索引。例如集合长度是4,就不能指,就不能指定替换索引为定替换索引为4的元素的元素-也就是说也就是说,set(int index, Object element)方法不会改变方法不会改变List集合的长度。集合的长度。sort()和和replaceAll()List的的listIterator()与与Set只提供了一个只提供了一个Iterator()方法不同,方法不同,List还额外还

59、额外提供了一个提供了一个ListIterator()方法,该方法返回一个()方法,该方法返回一个ListIterator对象,对象,ListIterator接口继承了接口继承了Iterator接口接口,提供了专门操作,提供了专门操作List的方法。的方法。ListIterator接口在接口在Iterator接口基础上增加了如下方法。接口基础上增加了如下方法。p boolean hasPrevious():返回该迭代器关联的集合返回该迭代器关联的集合是否还有上一个元素。是否还有上一个元素。p Object previous(): 返回该迭代器的上一个元素。返回该迭代器的上一个元素。p void

60、add(Object o):在指定位置插入一个元素。在指定位置插入一个元素。拿拿ListIterator与普通的与普通的Iterator对比,不难发现对比,不难发现ListIterator增加了向前迭代的功能(增加了向前迭代的功能(Iterator只能向后只能向后迭代),而且迭代),而且ListIterator还可通过还可通过add()方法向方法向List集集合中添加元素(合中添加元素(Iterator只能删除元素)。只能删除元素)。从程序中也可以看出,刚开始也需要正向迭代,即先使用从程序中也可以看出,刚开始也需要正向迭代,即先使用next()方法进行迭代,在迭代过程中可以使用方法进行迭代,在

温馨提示

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

评论

0/150

提交评论