1、集合1. java 集合大致上可分为三个体系:Set、List 和 Map。其中,a) Set 代表无序、不可重复的集合;b) List 代表有序、重复的集合;c) Map 代表有映射关系的集合。从 jdk1.5 之后,java 有增加了 Queue 体系集合,代表一种队列集合的实现。2. 数组虽然也可以保存多个对象,但是数组一经初始化,长度便不可变化,如果需要保存个数变化的数据,数组就无能为力了;而且数组无法保存具有映射关系的数据。3. 集合类与数组不一样,数组既可以保存对象,也可以保存基本类型数据,但是集合只能保存对象(实际上是保存对象的引用变量,单通常习惯上认为集合里保存的是对象) 。4
2、. java 的集合类主要由两个接口派生而出:Collection 和 Map,这两个接口是 java 集合框架的根接口,这两个接口又包含了一些子接口或实现类。CollectionSet List QueueEnumSetSortedSetHashSetTreeSetLinkedHashSetArrayListVectorLinkedListStackDequePriorityQueueCollection 集合体系继承树MapEnumMapHashtableWeakHashMapIdentityHashMapSortedMapHashMapProperties TreeMap LinkedH
3、ashMapMap 集合体系继承树三类集合的形象比喻Set 集合类似于一个罐子,把一个对象添加到 Set 集合时,Set 无法记住添加这个元素的顺序,所以 Set 里的元素不能重复(否则系统无法准确识别这个元素);List 集合非常像一个数组,它可以记住每次添加元素的顺序,只是 List 的长度可变;Map 集合也像一个罐子,只是它里面的每项数据都有两个值组成。三种集合框架的元素访问方式如果访问 List 集合中的元素,可以直接根据元素的索引来访问;如果需要访问 Map 集合的元素,可以根据每项元素的 key 来访问其 value;如果希望访问 Set 集合中的元素,则只能根据元素本身来访问(
4、这也是 Set 里不允许重复元素的原因)。Collection 接口1. Collection 接口是 List、Set 和 Queue 的父接口,该接口定义的方法既可用于 Set 操作,也可用于 List 和 Queue 操作。2. Collection 接口定义了一系列的操作集合元素的方法:a) boolean addAll(Collection c):把集合 c 里的所有元素添加到指定集合中,如果添加成功返回 true。b) boolean add(Object o):向集合里添加一个元素,如果添加成功返回 true。c) void clear():清除集合里所有元素,将集合长度变为 0
5、.d) boolean containsAll(Collection c):判断集合是否包含集合 c 里的所有元素。e) boolean isEmpty():判断集合是否为空。集合长度为 0 则返回 true。f) Iterator iterator():返回一个 Iterator 对象,用于遍历集合里的元素。g) boolean remove(Object o):删除集合中指定元素 o,当集合中包含了多个 o 时,这些元素将被全部删除。h) boolean removeAll(Collection c):从集合中删除集合 c 里包含的所有元素。i) boolean retainAll(Col
6、lection c):删除集合中集合 c 不包含的元素(相当于求当前集合和 c 的交集) 。j) int size():返回集合里元素的个数。k) Object toArray():把集合转换成一个数组,所有集合元素变成对应的数组元素。集合对象的输出当我们使用 System.out.println()方法来输出一个集合对象时将输出ele1,ele2,ele3的形式,这是因为 Collection 的实现类重写了 toString 方法,可以一次性输出集合中的所有元素。使用 Iterator 遍历集合元素1. Iterator 主要用于遍历(就是迭代访问)Collection 集合中的元素,It
7、erator对象也被称为迭代器。2. Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口。3. Iterator 接口里定义了如下三个方法:a) boolean hasNext():如果被迭代的集合元素还没有被遍历,返回 ture。b) Object next():返回集合里下一个元素。c) void remove():删除集合里上一次 next 方法返回的元素。4. 当使用 Iterator 来迭代访问 Collection 集合元素的时候,集合里的元素不能被改变,只有通过 Iterator 的 rem
8、ove 方法来删除上一次 next 方法返回的集合元素才可以,否则将会引起修改不当异常(java.util.ConcurrentModificationException)。5. Iterator 采用的是快速失败(fail-fast)机制,一旦在迭代过程中检测到集合元素已经被修改,程序立即引发异常,而不是显示修改后的结果,这样可以避免资源共享而引发的潜在问题。使用 foreach 循环遍历集合元素for(Object obj : c)使用 foreach 循环迭代集合元素时,集合也不能被改变,否则也会引起上述异常。 Set 接口1. Set 集合与 Collection 基本完全一样,它没有
9、提供任何额外的方法,实际上,除了行为不同(不允许重复) ,Set 就是 Collection。2. Set 集合不允许包含相同元素,如果试图把两个相同元素加入同一个 Set,则添加操作失败,add 方法返回 false,新元素无法加入。3. Set 判断两个对象是否相同不是使用=运算符,而是根据 equals 方法。换句话说,如果两个对象用 equals 方法判断返回 true,Set 就不会接受这两个对象同时存在其中。反之,如果两个对象用 equals 方法比较返回 false,即使这两个对象是同一个对象,Set 也会把它们当做两个对象处理。HashSet 类1. HashSet 类是 Se
10、t 接口的典型实现,大多数时候使用 Set 集合时就是用这个实现类。HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。2. HashSet 具有以下的特点:a) 不能保证元素的排列顺序,顺序有可能发生变化。b) HashSet 不是同步的,如果多个线程同时访问一个 HashSet,如果有两条或两条以上的线程同时修改了 HashSet 集合,必须通过代码来保证同步。c) 集合元素可以是 null。3. 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode()方法来得到该对象的 hashCode 值,然后根据该 hashCo
11、de 值来决定对象在 HashSet 里的存储位置。如果有两个元素通过 equals 方法比较返回 true,但他们的hashCode()方法返回值不等,HashSet 将会把它们存储在不同的位置,也就可以添加成功。4. 所以,HashSet 集合判断两个元素相等的标准是通过 equals 方法比较相等,并且两个对象的 hashCode 方法返回值也相等。5. 根据例子我们可以知道:当将一个对象放入 HashSet 时,如果重写该对象的equals 方法,也应该重写其 hashCode 方法,规则是,如果两个对象通过 equals方法比较返回 true,则这两个对象的 hashCode 方法返
12、回值也应该相同。6. 下面两种情况是不合适的:a) 两个对象通过 equals 方法比较返回 true(实际上是同一个对象) ,但是hashCode 方法返回值不同,这将导致 HashSet 将同一个对象分别放在不同的位置,这与 Set 不允许重复的思想有出入。b) 两个对象返回相同的 hashCode,但通过 equals 方法比较返回 false,这将使得 HashSet 在一个桶(bucket,HashSet 中每个能存储元素的槽位(slot)通常称为桶)内放入多个元素,导致性能下降很多。LinkedHashSet1. LinkedHashSet 是 HashSet 的子类,也是根据元素
13、的 hashCode 值来决定元素的存储位置,但它同时还使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。也就是说,当遍历 LinkedHashSet 集合里的元素时,将会按照元素的添加顺序来访问集合里的元素。2. 由于 LinkedHashSet 需要维护元素的插入顺序,因此性能略低于 HashSet,但是在迭代访问全部元素时将有很好的性能。TreeSet 类TreeSet 是 SortedSet 接口的唯一实现,可以确保集合元素处于排序状态。与前面的HashSet 集合相比,TreeSet 还提供了几个额外的方法:a) Comparator comparator():返回当前
14、 Set 的比较排序器 Comparator,或者返回null 表示以自然排序。b) Object first():返回集合中的第一个元素。c) Object last():返回集合中最末一个元素。d) Object lower(Object e):返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,参考元素并不需要是 TreeSet 元素)。e) Object higher(Object e):返回集合中位于指定元素之后的元素(即大于指定元素的最小元素,参考元素不需要是 TreeSet 的元素)。f) SortedSet subSet(fromElement,toElement):返
15、回此 Set 的子集合,范围从fromElement(包含)到 toElement(不包含) 。g) SortedSet headSet(toElement):返回此 Set 的子集,由小于 toElemnet 的元素组成。h) SortedSet tailSet(fromElement):返回此 Set 的子集,由大于或等于fromElement 的元素组成。TreeSet 的排序TreeSet 采用红黑树的数据结构对元素进行排序。TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下采用自然排序。自然排序TreeSet 会调用集合元素的 compareTo(Object obj)
16、方法来比较元素之间的大小关系,然后将集合元素按升序排列,这种方式就是自然排序。java 提供了一个 Comparable 接口,该接口里定义了一个 compareTo(Object obj)方法,该方法返回一个整数值,实现该接口的类必须实现该方法,实现了该接口的类的对象就可以比较大小。调用该方法时,如 pareTo(obj2),如果该方法返回 0,则表明两个对象相等;如果该方法返回正整数,表明 obj1 大于 obj2;如果返回一个负整数,则表明obj1 小于 obj2.实现了 Comparable 接口的常用类1. BigDecimal、BigInteger 以及所有数值型对应的包装类:按照
17、数值大小比较;2. Character:按字符的 Unicode 值进行比较;3. Boolean:true 大于 false;4. String:按字符串中字符的 Unicode 值进行比较;5. Date、Time:后面的时间、日期比前面的时间、日期大。定制排序1. 如果试图把一个对象添加进 TreeSet,该对象的类必须实现 Comparable 接口,否则 将会抛出异常。其实,只有第一个元素可以无需实现 Comparable 接口。2. TreeSet 中的元素应该是同一个类的对象,否则也会引发 ClassCastException 异常。这是因为大部分类在实现 compareTo 方
18、法时,都需要将被比较的对象强制类型转换为相同类型,因为只有相同类的实例才可以比较大小。3. 因此如果一定要向 TreeSet 中添加多种对象(必须都是程序员自己定义) ,则这些类中实现 compareTo 方法时,不要进行强制类型转换。4. 当需要把一个对象放入 TreeSet 时,应该重写该对象的 equals 方法,并且应保证该方法与 compareTo 方法有一致的结果,规则是:如果两个对象通过 equals 比较返回 true,则这两个对象用 compareTo 比较应该返回 0。5. 如果两个对象用 equals 方法返回 true,而用 compareTo 方法不返回 0 时,将导
19、致 TreeSet 将同一个对象保存在不同的位置两次,这与 Set 的规则有点出入,并且当我们修改一个元素时,另一个位置的元素也会随之修改(因为它们根本就是同一个对象) ,这样做会有很多隐患。6. 如果两个方法的 equals 方法返回 false,而 compareTo 方法比较却返回 0,将会导致 TreeSet 在同一个位置放入两个对象,但实际上却行不通,所以处理起来非常复杂。7. 如果向 TreeSet 中添加了一个可变对象后,并且后面的程序修改了该可变对象的属性,导致它与其他元素的大小顺序发生了变化,TreeSet 不会做出相应的顺序调整,这样就完全有可能发生 TreeSet 里保存的两个元素用 equals 方法比较返回true,compareTo 方法比较返回 0.