一、初识:
集合类是 Java基础技术中十分重要的内容。 Java集合类封装了集合中常用数据结构和算法,所以在Java的学习过程中得好好学习Java的集合类。
首先,看一张关于Java集合类的表
| Implementations | |||||
---|---|---|---|---|---|---|
Hash Table | Resizable Array | Balanced Tree | Linked List | Hash Table + LinkedList | ||
Interfaces | Set | HashSet |
| TreeSet |
| LinkedHashSet |
List |
| ArrayList |
| LinkedList |
| |
Map | HashMap |
| TreeMap |
| LinkedHashMap |
Java在设计集合结构时,把集合划成 3类:第一种 Set,普通的无序集;第二种 List,偏序集;第三种 Map,有序对的集合。 其中 Set和 List都继承自 Collection接口, Map没有从 Collection继承。这样做也是没办法的事,因为 Map并不是一个通常意义的集合,它的元素是一个 key-value-pair,而 Collection根本就不是 Map,它还没有 key的概念。虽然 Collection和 Map彼此没有继承关系,但它们有大量同名的方法。值得注意的是, Map提供了 keySet()和 values()两个方法,分别返回一个 key的集合和值的集合。
Collection与Map关系如下:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
集合框架的结构图如下所示:
二、进阶:
1. 接口
整个Java容器类的基础是容器接口(例如Collection,Map等接口),而不是类。使用接口的最大好处在于将容器的实现与容器的接口分开,这就意味着你可以使用相同的方法访问容器而不用关心容器是由什么样的数据结构实现的。同样,Iterator接口也使得用户可以使用相同的方法访问不同的容器类。以上这些是通用算法的基础。
1.1 Collection接口
Collection接口有如下基本方法:
boolean add(Object obj):如果添加对象后,集合确实发生了变化,则返回true;否则返回false
Iterator iterator():返回一个实现了Iterator接口的对象
此外,还有int size(),boolean isEmpty(),boolean contains(Object obj),void clear()等许多有用的方法
1.2 Map接口
Map用于存放关键字/值对。有如下基本方法:
Object get(Object key)
Object put(Object key,Object balue)
Set keySet()
Set entrySet()
此外,还有其他有用的方法。需要注意的是,从表面看它似乎就是一种由键值对构成的集合,但实际上并不是这样。不过另一方面假如将Map的某一部分看作集合,有时候也还是显得非常方便的。换言之你可以创建一个集合用它来表达Map的那一部分。综上所述,一个Map可以返回的东西包括它的键值构成的一个Set、由它的值构成的一个集合或者由它的键值对构成的一个Set。
1.3 Iterator接口
Iterator接口有下面3个基本方法:
Object next():返回迭代器刚越过的元素的引用
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
注意:Java中的迭代器与STL中的迭代器在概念上有很重要的区别。在STL中,迭代器类似于数组的索引,使用这种迭代器可以查看存放在该位置上的元素(类似于通过数组索引i来访问c[i]一样)。Java中的迭代器并不这样运行。查看与位置的变化紧密的结合在一起。每次通过next()访问一个元素的同时,迭代器的位置会自动向前走一步。
这个问题可以这样理解:Java中的迭代器指向的位置并不是元素,而是元素之间。这样,每次调用next()时,迭代器便越过下一个元素,同时返回它刚越过的那个元素的引用。
迭代器的典型应用
- Iterator it=c.iterator();
- while(it.hasNext())
- {
- Object obj=it.next();
- //do something with obj
- }
1.4 子接口
1.4.1 List接口
List从Collection接口中分立出来是因为List的特点——有序的集合。这里指的有序并不是按照大小排好序的(Sorted),而是指集合是可以以确定的顺序访问的序列。针对List的这个特点,它比Collection接口增加了通过索引进行操作的方法。例如,add、remove、get、set等方法的参数表中都可以加入索引的数值,从而操作处在索引位置处的元素。
1.4.2 Set 接口
Set与List的不同,它里面的元素是无序的;所以,不能通过任何索引的方法来操作Set对象
1.4.3 ListIterator 接口
使用与List的迭代器,比Iterator接口增加了一些方法(例如add()等)。此外,由于List是双向表,所以还增加了 Object previous()和boolean hasPrevious()方法,用法与next()和hasNext()一样。
1.4.4 SortedMap 接口
包含如下基本方法:
Comparator comparator()
Object firstKey()
Object lastKey()
2. 抽象容器类
2.1 抽象容器类包括AbstractCollection,AbstractList,AbstractSet等等
2.2 为什么要有抽象结合类?
例如Collection接口中定义了许多有用的方法,如果实现Collection接口的每个类都自行实现这么多的方法,那将是非常麻烦的。为了使实现Collection接口的类的实现更容易,AbstractCollection类让一些基本方法(比如add()和 iterator())变成了抽象的方法,而利用这些基本方法的其他方法(例如addAll()等等)则具体实现了。
3. 具体的容器
3.1 ArrayList 与LinkedList
都是实现了List接口的类,是有序集。List接口支持通过索引的方法来访问元素,对于这一点,ArrayList没有任何问题;但是对于LinkedList则有很大的问题,链表本身不应该支持随机存储,但是作为List的一个实现,链表也提供了对随机访问的支持,但是效率很低。每次通过索引的方法都是进行一次遍历。我认为,其实就不应该让链表支持随机访问;而Java这样实现我想是因为整个集合框架的体系,使得链表与数组可以使用同样的方法使用。综上所述,对于LinkedList最好不使用随机访问,而使用迭代器。
3.2 TreeSet
3.2.1 TreeSet 是SortedSet的一个实现。
根据数据结构的知识可以知道,树的效率非常高,而且Java标准库中有TreeSet这样的类,以后应该尽量使用 TreeSet来提高程序的效率。
3.2.2 需要注意的是:TreeSet作为有序集,它通过compareTo或者Comparator来将集合元素排序。
任何具有相同比较值的元素(无论它们是否equals()),在TreeSet中都作为同一个元素,从而不能有重复。这样以来,即使是不同的对象也不能加入到集合中,这一点有时候很不方便。我在编写A*算法时,不同状态有时候对应着同一个启发函数值,那么这些不同的状态就无法加入到 TreeSet中。
3.3 HashSet
3.3.1 HashSet是非常高效的数据结构
与TreeSet不同,HashSet是比较对象的equals()方法来区分不同的对象。这样只有真正不同的对象才能不被重复的加入到集合中。
3.3.2 需要注意的是
HashSet 效率非常高,但是对象的hashCode函数不好确定。一般默认的对象的hashCode函数是根据对象的内存地址得到的。好的hashCode函数是 HashSet成功运用的关键。
三、总结:
1. 集合
-
常见集合操作包括:添加对象、删除对象、验证对象内容、检索对象和迭代对象。
-
“collection” 的 3 种含义如下:
1. 集合。表示一种数据结构,对象存储在其中;
2. Collection。java.util接口,Set和List扩展自它;
3. Collections。一个类,它拥有静态集合实用工具方法。
-
集合的 4 种基本形式包括 List 、 Set 、 Map 和 Queue 。
1. List。它是ordered的,允许重复,带有索引;
2. Set。可以是也可以不是ordered的和/或sorted的,但不允许重复;
3. Map。具有键,可以是也可以不是ordered的和/或sorted的,但不允许重复的键;
4. Queue。根据FIFO原则或优先权排序。
-
集合的 4 种基本子类型是 Sorted 、 Unsorted 、 Ordered 和 Unordered 。
1. Ordered。以一种特定的、非随机的顺序迭代遍历集合;
2. Sorted。以sorted的顺序迭代遍历集合。
-
排序可以按字母、数字或程序员定义的标准进行。
2. 常见集合类的主要属性
-
ArrayList :快速迭代和快速随机访问;
-
Vector :它就像一个稍慢一些的 ArrayList ,但具有同步方法;
-
LinkedList :适合于向尾部添加元素,包括栈和队列;
-
HashSet :快速访问,保证没有重复,不提供任何顺序;
-
LinkedHashSet :没有重复,按照插入顺序迭代;
-
TreeSet :没有重复,按照排序的顺序迭代;
-
HashMap :最快速地更新键 / 值对。允许一个 null 键和多个 null 值;
-
Hashtable :就像稍慢一些的 HashMap (与 Vector 一样,由于其同步方法)。不允许 null 值或 null 键;
-
LinkedHashMap :迭代更快,按照插入顺序或者最近访问的顺序迭代。允许一个 null 键或 null 值;
-
TreeMap :一种排序映射;
-
PriorityQueue :按照元素的优先级排序的 “ 待执行任务 ” 的列表。
3. 使用集合类
-
集合只能保存对象,但基本类型可以被自动装箱;
-
用增强型 for 循环,或通过使用 hasNext() 和 next() 的迭代器进行迭代;
-
hasNext() 用来判断是否还有更多的元素存在,迭代器不向前移动;
-
next() 返回下一个元素并向前移动迭代器;
-
为了正确地工作, Map 的键必须重写 equals() 和 hashCode() 方法;
-
队列使用 offer() 添加元素,使用 poll() 删除队列头,使用 peek() 查找队列头;
-
在 Java6 中, TreeSet 和 TreeMap 具有新的导航方法,比如 floor() 和 higher() ;
-
可以创建 / 扩展 TreeSet 和 TreeMap 的 “ 后备 ” 子副本。
4. 排序和查找数组与List
-
排序可以按自然顺序,也可以通过一个 Comparable 或多个 Comparator 进行;
-
使用 compareTo() 实现 Comparable ,但只提供一种排序顺序;
-
创建多个 Comparator 来以多种方式排序类,实现 compare() ;
-
要进行排序和查找, List 的元素必须是可比较的;
-
要进行查找,数组和 List 必须首先进行排序。
5. 实用工具类:Collections和Arrays
-
这两个 java.util 类都提供:
1. sort()方法。使用Comparator或自然顺序进行排序。
2. binarySearch()方法。查找预先排序的数组或List。
-
Arrays.asList() 根据数组创建 List ,并将二者链接起来;
-
Collections.reverse() 颠倒 List 中元素的顺序;
-
Collections.reverseOrder() 返回以反序排序的 Comparator ;
-
List 和 Set 具有创建数组的 toArray() 方法。